RE: [PATCH V3 3/5] x86/efi: Permanently save the EFI_MEMORY_MAP passed by the firmware

2018-09-06 Thread Prakhya, Sai Praneeth
> >> I agree. Keep it simple. If the EFI crap fails, then assist with the
> >> reboot and otherwise just kill it.
> >
> > The reasons for saving old memory map are (in my view, these are the
> > less important ones because they are very unlikely to happen)
> >
> > 1. Make sure that a memory descriptor exists for the physical address
> > that was faulted on (EFI Memory Map could sometime have holes).
> > Assuming a case that the physical address that caused page fault
> > doesn't have a valid efi memory descriptor, the efi page fault handler 
> > shouldn't
> take any action because it hasn't triaged the problem yet.
> >
> > 2. Make sure that the faulted physical address is _not_ efi runtime service
> code/data region.
> > Efi runtime service code/data regions are always mapped by kernel in
> > efi_pgd and accesses to these regions should _never_ page fault.
> > Assuming that something like this happens, efi page fault handler
> > shouldn't take any action because it's not any illegal access by firmware 
> > but it's
> a kernel bug.
> >
> 
> What about attempts to modify code regions or attempts to execute data
> regions? What kind of fault will that trigger, and are they being handled at 
> the
> moment?

AFAIK, at least in the x86 world, attempts to write to read only regions or 
attempts 
to execute XP (execute protected) pages will result in page fault and I don't 
think 
we are handling them.

> 
> As I pointed out, EFI runtime services code may legally access the stack or
> dereference pointer arguments, but could still contain bugs that result in 
> out of
> bounds accesses or writes to read-only regions.

Yes, agreed. In fact, I did see these bugs.

> So I don't really care about the address of the illegal access, any fault that
> occurs while running in the firmware should be treated the same.

Ok.. makes sense.

> In fact, cross
> referencing the value of IP with RuntimeServicesCode regions may be more
> useful

This is to verify that firmware is indeed executing code from 
RuntimeServicesCode
regions when it faulted. Is that correct? Or did you mean something else?

> > That said, a more important reason (in my view) is to print out the
> > memory descriptor that we faulted on. This is a *proof* showing that
> > it's buggy firmware that caused page fault and hence is not a kernel
> > bug. This proof is important because whenever a stack trace is printed
> > with some efi function, kernel is the usual suspect and hence we need to 
> > show
> that it's not kernel fault. It could also help firmware engineers to fix the 
> bug
> easily.
> >
> > dmesg would show something like this when buggy efi_reset_system()
> accesses reserved region:
> >
> > [  296.141511] efi: EFI Memory Descriptor for offending PA is:
> > [  296.141844] efi: [Reserved   |   |  |  |  |  |  |  |   
> > |WB|WT|WC|UC]
> range=[0x7e915000-0x7e933fff] (0MB)
> > [  296.142522] efi: efi_reset_system() buggy! Reboot through BIOS
> >
> > So, I would be concerned if we miss this proof.
> >
> 
> You can dump the entire memory map by putting efi=debug on the kernel
> command line, so all we need to do is report the physical address, and you can
> easily figure out for yourself which memory map entry covers it.

That's true. In fact, that's how I debugged this issue and hence thought that 
it might be 
useful to have all that info at one place (i.e. in efi page fault handler).
But, as you said, to make the code look simpler, I will roll out a V4 without 
saving 
original memory map.

Regards,
Sai


Re: [PATCH V3 3/5] x86/efi: Permanently save the EFI_MEMORY_MAP passed by the firmware

2018-09-06 Thread Ard Biesheuvel
On 5 September 2018 at 19:53, Prakhya, Sai Praneeth
 wrote:
>> On Wed, 5 Sep 2018, Ard Biesheuvel wrote:
>> > On 5 September 2018 at 14:56, Peter Zijlstra  wrote:
>> > > On Wed, Sep 05, 2018 at 02:27:49PM +0200, Ard Biesheuvel wrote:
>> > >> Would we still need to preserve the old memory map in that case?
>> > >
>> > > I thought the reason for having this was being able to know the
>> > > fault is in an EFI area. But of course, I'm not wel versed in this
>> > > whole EFI crapola.
>> >
>> > I'm not entirely sure whether that really matters. The EFI services
>> > access the stack and can access byref/pointer arguments which are not
>> > covered by the EFI memory map as runtime services code/data, and so
>> > they can trigger page faults by running off the vmapped stack or
>> > writing to const byref arguments.
>> >
>> > EFI runtime services using boot services regions after they are no
>> > longer available are a known source of headaches, but I don't see why
>> > we should restrict ourselves to such cases if we bother to wire up
>> > fault handling specifically for EFI services calls.
>> >
>> > So any page or permission fault occurring in the context of a EFI
>> > runtime services invocation should be treated the same, I think.
>>
>> I agree. Keep it simple. If the EFI crap fails, then assist with the reboot 
>> and
>> otherwise just kill it.
>
> The reasons for saving old memory map are
> (in my view, these are the less important ones because they are very unlikely 
> to happen)
>
> 1. Make sure that a memory descriptor exists for the physical address that was
> faulted on (EFI Memory Map could sometime have holes). Assuming a case that 
> the
> physical address that caused page fault doesn't have a valid efi memory 
> descriptor, the
> efi page fault handler shouldn't take any action because it hasn't triaged 
> the problem yet.
>
> 2. Make sure that the faulted physical address is _not_ efi runtime service 
> code/data region.
> Efi runtime service code/data regions are always mapped by kernel in efi_pgd 
> and accesses
> to these regions should _never_ page fault. Assuming that something like this 
> happens,
> efi page fault handler shouldn't take any action because it's not any illegal 
> access by firmware
> but it's a kernel bug.
>

What about attempts to modify code regions or attempts to execute data
regions? What kind of fault will that trigger, and are they being
handled at the moment?

As I pointed out, EFI runtime services code may legally access the
stack or dereference pointer arguments, but could still contain bugs
that result in out of bounds accesses or writes to read-only regions.
So I don't really care about the address of the illegal access, any
fault that occurs while running in the firmware should be treated the
same. In fact, cross referencing the value of IP with
RuntimeServicesCode regions may be more useful than trying to infer
whether the access itself was to a valid region.


> Generally, the above two scenarios should never happen. I am just being 
> paranoid and wanted
> to make sure that the efi page fault handler is fixing the right firmware bug 
> that I came across
> and not something else. I also agree that, we could make the patch set and 
> efi page fault handler
> much simpler by not saving old memory map. So, I am OK if we are not checking 
> for the above
> two scenarios. If they are really needed, we could add them later.
>
> That said, a more important reason (in my view) is to print out the memory 
> descriptor that
> we faulted on. This is a *proof* showing that it's buggy firmware that caused 
> page fault and
> hence is not a kernel bug. This proof is important because whenever a stack 
> trace is printed
> with some efi function, kernel is the usual suspect and hence we need to show 
> that it's not
> kernel fault. It could also help firmware engineers to fix the bug easily.
>
> dmesg would show something like this when buggy efi_reset_system() accesses 
> reserved region:
>
> [  296.141511] efi: EFI Memory Descriptor for offending PA is:
> [  296.141844] efi: [Reserved   |   |  |  |  |  |  |  |   
> |WB|WT|WC|UC] range=[0x7e915000-0x7e933fff] (0MB)
> [  296.142522] efi: efi_reset_system() buggy! Reboot through BIOS
>
> So, I would be concerned if we miss this proof.
>

You can dump the entire memory map by putting efi=debug on the kernel
command line, so all we need to do is report the physical address, and
you can easily figure out for yourself which memory map entry covers
it.


RE: [PATCH V3 3/5] x86/efi: Permanently save the EFI_MEMORY_MAP passed by the firmware

2018-09-05 Thread Prakhya, Sai Praneeth
> On Wed, 5 Sep 2018, Ard Biesheuvel wrote:
> > On 5 September 2018 at 14:56, Peter Zijlstra  wrote:
> > > On Wed, Sep 05, 2018 at 02:27:49PM +0200, Ard Biesheuvel wrote:
> > >> Would we still need to preserve the old memory map in that case?
> > >
> > > I thought the reason for having this was being able to know the
> > > fault is in an EFI area. But of course, I'm not wel versed in this
> > > whole EFI crapola.
> >
> > I'm not entirely sure whether that really matters. The EFI services
> > access the stack and can access byref/pointer arguments which are not
> > covered by the EFI memory map as runtime services code/data, and so
> > they can trigger page faults by running off the vmapped stack or
> > writing to const byref arguments.
> >
> > EFI runtime services using boot services regions after they are no
> > longer available are a known source of headaches, but I don't see why
> > we should restrict ourselves to such cases if we bother to wire up
> > fault handling specifically for EFI services calls.
> >
> > So any page or permission fault occurring in the context of a EFI
> > runtime services invocation should be treated the same, I think.
> 
> I agree. Keep it simple. If the EFI crap fails, then assist with the reboot 
> and
> otherwise just kill it.

The reasons for saving old memory map are
(in my view, these are the less important ones because they are very unlikely 
to happen)

1. Make sure that a memory descriptor exists for the physical address that was 
faulted on (EFI Memory Map could sometime have holes). Assuming a case that the 
physical address that caused page fault doesn't have a valid efi memory 
descriptor, the 
efi page fault handler shouldn't take any action because it hasn't triaged the 
problem yet.

2. Make sure that the faulted physical address is _not_ efi runtime service 
code/data region.
Efi runtime service code/data regions are always mapped by kernel in efi_pgd 
and accesses 
to these regions should _never_ page fault. Assuming that something like this 
happens, 
efi page fault handler shouldn't take any action because it's not any illegal 
access by firmware 
but it's a kernel bug.

Generally, the above two scenarios should never happen. I am just being 
paranoid and wanted 
to make sure that the efi page fault handler is fixing the right firmware bug 
that I came across 
and not something else. I also agree that, we could make the patch set and efi 
page fault handler 
much simpler by not saving old memory map. So, I am OK if we are not checking 
for the above 
two scenarios. If they are really needed, we could add them later.

That said, a more important reason (in my view) is to print out the memory 
descriptor that 
we faulted on. This is a *proof* showing that it's buggy firmware that caused 
page fault and 
hence is not a kernel bug. This proof is important because whenever a stack 
trace is printed 
with some efi function, kernel is the usual suspect and hence we need to show 
that it's not 
kernel fault. It could also help firmware engineers to fix the bug easily.

dmesg would show something like this when buggy efi_reset_system() accesses 
reserved region:

[  296.141511] efi: EFI Memory Descriptor for offending PA is:
[  296.141844] efi: [Reserved   |   |  |  |  |  |  |  |   |WB|WT|WC|UC] 
range=[0x7e915000-0x7e933fff] (0MB)
[  296.142522] efi: efi_reset_system() buggy! Reboot through BIOS

So, I would be concerned if we miss this proof.

Regards,
Sai


Re: [PATCH V3 3/5] x86/efi: Permanently save the EFI_MEMORY_MAP passed by the firmware

2018-09-05 Thread Thomas Gleixner
On Wed, 5 Sep 2018, Ard Biesheuvel wrote:
> On 5 September 2018 at 14:56, Peter Zijlstra  wrote:
> > On Wed, Sep 05, 2018 at 02:27:49PM +0200, Ard Biesheuvel wrote:
> >> Would we still need to preserve the old memory map in that case?
> >
> > I thought the reason for having this was being able to know the fault is
> > in an EFI area. But of course, I'm not wel versed in this whole EFI
> > crapola.
> 
> I'm not entirely sure whether that really matters. The EFI services
> access the stack and can access byref/pointer arguments which are not
> covered by the EFI memory map as runtime services code/data, and so
> they can trigger page faults by running off the vmapped stack or
> writing to const byref arguments.
> 
> EFI runtime services using boot services regions after they are no
> longer available are a known source of headaches, but I don't see why
> we should restrict ourselves to such cases if we bother to wire up
> fault handling specifically for EFI services calls.
> 
> So any page or permission fault occurring in the context of a EFI
> runtime services invocation should be treated the same, I think.

I agree. Keep it simple. If the EFI crap fails, then assist with the reboot
and otherwise just kill it.

Thanks,

tglx



Re: [PATCH V3 3/5] x86/efi: Permanently save the EFI_MEMORY_MAP passed by the firmware

2018-09-05 Thread Ard Biesheuvel
On 5 September 2018 at 14:56, Peter Zijlstra  wrote:
> On Wed, Sep 05, 2018 at 02:27:49PM +0200, Ard Biesheuvel wrote:
>> On 5 September 2018 at 00:12, Sai Praneeth Prakhya
>>  wrote:
>> > From: Sai Praneeth 
>> >
>> > The efi page fault handler that recovers from page faults caused by the
>> > firmware needs the original memory map passed by the firmware. It looks
>> > up this memory map to find the type of the memory region at which the
>> > page fault occurred. Presently, EFI subsystem discards the original
>> > memory map passed by the firmware and replaces it with a new memory map
>> > that has only EFI_RUNTIME_SERVICES_ regions. But illegal
>> > accesses by firmware can occur at any region. Hence, _only_ if
>> > CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS is defined, create a backup of the
>> > original memory map passed by the firmware, so that efi page fault
>> > handler could detect/recover from illegal accesses to *any* efi region.
>> >
>>
>> Why do we care about the memory map at all when a fault occurs during
>> the invocation of a EFI runtime service?
>>
>> I think reasoning about what went wrong and why, and distinguishing
>> between allowable and non-allowable faults is a slippery slope, so
>> [taking Thomas's feedback into account], I think we can simplify this
>> series further and just block all subsequent EFI runtime services
>> calls if any permission or page fault occurs while executing them.
>>
>> Would we still need to preserve the old memory map in that case?
>
> I thought the reason for having this was being able to know the fault is
> in an EFI area. But of course, I'm not wel versed in this whole EFI
> crapola.

I'm not entirely sure whether that really matters. The EFI services
access the stack and can access byref/pointer arguments which are not
covered by the EFI memory map as runtime services code/data, and so
they can trigger page faults by running off the vmapped stack or
writing to const byref arguments.

EFI runtime services using boot services regions after they are no
longer available are a known source of headaches, but I don't see why
we should restrict ourselves to such cases if we bother to wire up
fault handling specifically for EFI services calls.

So any page or permission fault occurring in the context of a EFI
runtime services invocation should be treated the same, I think.


Re: [PATCH V3 3/5] x86/efi: Permanently save the EFI_MEMORY_MAP passed by the firmware

2018-09-05 Thread Peter Zijlstra
On Wed, Sep 05, 2018 at 02:27:49PM +0200, Ard Biesheuvel wrote:
> On 5 September 2018 at 00:12, Sai Praneeth Prakhya
>  wrote:
> > From: Sai Praneeth 
> >
> > The efi page fault handler that recovers from page faults caused by the
> > firmware needs the original memory map passed by the firmware. It looks
> > up this memory map to find the type of the memory region at which the
> > page fault occurred. Presently, EFI subsystem discards the original
> > memory map passed by the firmware and replaces it with a new memory map
> > that has only EFI_RUNTIME_SERVICES_ regions. But illegal
> > accesses by firmware can occur at any region. Hence, _only_ if
> > CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS is defined, create a backup of the
> > original memory map passed by the firmware, so that efi page fault
> > handler could detect/recover from illegal accesses to *any* efi region.
> >
> 
> Why do we care about the memory map at all when a fault occurs during
> the invocation of a EFI runtime service?
> 
> I think reasoning about what went wrong and why, and distinguishing
> between allowable and non-allowable faults is a slippery slope, so
> [taking Thomas's feedback into account], I think we can simplify this
> series further and just block all subsequent EFI runtime services
> calls if any permission or page fault occurs while executing them.
> 
> Would we still need to preserve the old memory map in that case?

I thought the reason for having this was being able to know the fault is
in an EFI area. But of course, I'm not wel versed in this whole EFI
crapola.


Re: [PATCH V3 3/5] x86/efi: Permanently save the EFI_MEMORY_MAP passed by the firmware

2018-09-05 Thread Ard Biesheuvel
On 5 September 2018 at 00:12, Sai Praneeth Prakhya
 wrote:
> From: Sai Praneeth 
>
> The efi page fault handler that recovers from page faults caused by the
> firmware needs the original memory map passed by the firmware. It looks
> up this memory map to find the type of the memory region at which the
> page fault occurred. Presently, EFI subsystem discards the original
> memory map passed by the firmware and replaces it with a new memory map
> that has only EFI_RUNTIME_SERVICES_ regions. But illegal
> accesses by firmware can occur at any region. Hence, _only_ if
> CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS is defined, create a backup of the
> original memory map passed by the firmware, so that efi page fault
> handler could detect/recover from illegal accesses to *any* efi region.
>

Why do we care about the memory map at all when a fault occurs during
the invocation of a EFI runtime service?

I think reasoning about what went wrong and why, and distinguishing
between allowable and non-allowable faults is a slippery slope, so
[taking Thomas's feedback into account], I think we can simplify this
series further and just block all subsequent EFI runtime services
calls if any permission or page fault occurs while executing them.

Would we still need to preserve the old memory map in that case?

> Suggested-by: Matt Fleming 
> Based-on-code-from: Ricardo Neri 
> Signed-off-by: Sai Praneeth Prakhya 
> Cc: Al Stone 
> Cc: Borislav Petkov 
> Cc: Ingo Molnar 
> Cc: Andy Lutomirski 
> Cc: Bhupesh Sharma 
> Cc: Thomas Gleixner 
> Cc: Peter Zijlstra 
> Cc: Ard Biesheuvel 
> ---
>  arch/x86/include/asm/efi.h |  6 ++
>  arch/x86/platform/efi/efi.c|  2 ++
>  arch/x86/platform/efi/quirks.c | 48 
> ++
>  3 files changed, 56 insertions(+)
>
> diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
> index cec5fae23eb3..788ed4cbce22 100644
> --- a/arch/x86/include/asm/efi.h
> +++ b/arch/x86/include/asm/efi.h
> @@ -141,6 +141,12 @@ extern int __init efi_reuse_config(u64 tables, int 
> nr_tables);
>  extern void efi_delete_dummy_variable(void);
>  extern void efi_switch_mm(struct mm_struct *mm);
>
> +#ifdef CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS
> +extern void __init efi_save_original_memmap(void);
> +#else
> +static inline void __init efi_save_original_memmap(void) { }
> +#endif /* CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS */
> +
>  struct efi_setup_data {
> u64 fw_vendor;
> u64 runtime;
> diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
> index 9061babfbc83..7a3ea4cd5939 100644
> --- a/arch/x86/platform/efi/efi.c
> +++ b/arch/x86/platform/efi/efi.c
> @@ -946,6 +946,8 @@ static void __init __efi_enter_virtual_mode(void)
>
> pa = __pa(new_memmap);
>
> +   efi_save_original_memmap();
> +
> /*
>  * Unregister the early EFI memmap from efi_init() and install
>  * the new EFI memory map that we are about to pass to the
> diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
> index 844d31cb8a0c..36b0b042ba56 100644
> --- a/arch/x86/platform/efi/quirks.c
> +++ b/arch/x86/platform/efi/quirks.c
> @@ -654,3 +654,51 @@ int efi_capsule_setup_info(struct capsule_info 
> *cap_info, void *kbuff,
>  }
>
>  #endif
> +
> +#ifdef CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS
> +
> +static bool original_memory_map_present;
> +static struct efi_memory_map original_memory_map;
> +
> +/*
> + * The efi page fault handler that recovers from page faults caused by
> + * buggy firmware needs original memory map passed by firmware. Hence,
> + * build a new EFI memmap that has all entries and save it for later use.
> + */
> +void __init efi_save_original_memmap(void)
> +{
> +   efi_memory_desc_t *md;
> +   void *remapped_phys, *new_md;
> +   phys_addr_t new_phys, new_size;
> +
> +   new_size = efi.memmap.desc_size * efi.memmap.nr_map;
> +   new_phys = efi_memmap_alloc(efi.memmap.nr_map);
> +   if (!new_phys) {
> +   pr_err("Failed to allocate new EFI memmap\n");
> +   return;
> +   }
> +
> +   remapped_phys = memremap(new_phys, new_size, MEMREMAP_WB);
> +   if (!remapped_phys) {
> +   pr_err("Failed to remap new EFI memmap\n");
> +   __free_pages(pfn_to_page(PHYS_PFN(new_phys)), 
> get_order(new_size));
> +   return;
> +   }
> +
> +   new_md = remapped_phys;
> +   for_each_efi_memory_desc(md) {
> +   memcpy(new_md, md, efi.memmap.desc_size);
> +   new_md += efi.memmap.desc_size;
> +   }
> +
> +   original_memory_map.late = 1;
> +   original_memory_map.phys_map = new_phys;
> +   original_memory_map.map = remapped_phys;
> +   original_memory_map.nr_map = efi.memmap.nr_map;
> +   original_memory_map.desc_size = efi.memmap.desc_size;
> +   original_memory_map.map_end = remapped_phys + new_size;
> +   original_memory_map.desc_version = efi.memmap.desc_version;
> +
> +   

Re: [PATCH V3 3/5] x86/efi: Permanently save the EFI_MEMORY_MAP passed by the firmware

2018-09-05 Thread Peter Zijlstra
On Tue, Sep 04, 2018 at 03:12:27PM -0700, Sai Praneeth Prakhya wrote:
> +void __init efi_save_original_memmap(void)
> +{
> + efi_memory_desc_t *md;
> + void *remapped_phys, *new_md;
> + phys_addr_t new_phys, new_size;
> +
> + new_size = efi.memmap.desc_size * efi.memmap.nr_map;
> + new_phys = efi_memmap_alloc(efi.memmap.nr_map);
> + if (!new_phys) {
> + pr_err("Failed to allocate new EFI memmap\n");
> + return;
> + }
> +
> + remapped_phys = memremap(new_phys, new_size, MEMREMAP_WB);
> + if (!remapped_phys) {
> + pr_err("Failed to remap new EFI memmap\n");
> + __free_pages(pfn_to_page(PHYS_PFN(new_phys)), 
> get_order(new_size));
> + return;
> + }
> +
> + new_md = remapped_phys;
> + for_each_efi_memory_desc(md) {
> + memcpy(new_md, md, efi.memmap.desc_size);
> + new_md += efi.memmap.desc_size;
> + }

Should we ioremap_prot(remapped_phys, new_size, PROT_NONE), here? Such
that nobody can accidentally use this thing?

> + original_memory_map.late = 1;
> + original_memory_map.phys_map = new_phys;
> + original_memory_map.map = remapped_phys;
> + original_memory_map.nr_map = efi.memmap.nr_map;
> + original_memory_map.desc_size = efi.memmap.desc_size;
> + original_memory_map.map_end = remapped_phys + new_size;
> + original_memory_map.desc_version = efi.memmap.desc_version;
> +
> + original_memory_map_present = true;
> +}
> +#endif /* CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS */
> -- 
> 2.7.4
> 


[PATCH V3 3/5] x86/efi: Permanently save the EFI_MEMORY_MAP passed by the firmware

2018-09-04 Thread Sai Praneeth Prakhya
From: Sai Praneeth 

The efi page fault handler that recovers from page faults caused by the
firmware needs the original memory map passed by the firmware. It looks
up this memory map to find the type of the memory region at which the
page fault occurred. Presently, EFI subsystem discards the original
memory map passed by the firmware and replaces it with a new memory map
that has only EFI_RUNTIME_SERVICES_ regions. But illegal
accesses by firmware can occur at any region. Hence, _only_ if
CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS is defined, create a backup of the
original memory map passed by the firmware, so that efi page fault
handler could detect/recover from illegal accesses to *any* efi region.

Suggested-by: Matt Fleming 
Based-on-code-from: Ricardo Neri 
Signed-off-by: Sai Praneeth Prakhya 
Cc: Al Stone 
Cc: Borislav Petkov 
Cc: Ingo Molnar 
Cc: Andy Lutomirski 
Cc: Bhupesh Sharma 
Cc: Thomas Gleixner 
Cc: Peter Zijlstra 
Cc: Ard Biesheuvel 
---
 arch/x86/include/asm/efi.h |  6 ++
 arch/x86/platform/efi/efi.c|  2 ++
 arch/x86/platform/efi/quirks.c | 48 ++
 3 files changed, 56 insertions(+)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index cec5fae23eb3..788ed4cbce22 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -141,6 +141,12 @@ extern int __init efi_reuse_config(u64 tables, int 
nr_tables);
 extern void efi_delete_dummy_variable(void);
 extern void efi_switch_mm(struct mm_struct *mm);
 
+#ifdef CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS
+extern void __init efi_save_original_memmap(void);
+#else
+static inline void __init efi_save_original_memmap(void) { }
+#endif /* CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS */
+
 struct efi_setup_data {
u64 fw_vendor;
u64 runtime;
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 9061babfbc83..7a3ea4cd5939 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -946,6 +946,8 @@ static void __init __efi_enter_virtual_mode(void)
 
pa = __pa(new_memmap);
 
+   efi_save_original_memmap();
+
/*
 * Unregister the early EFI memmap from efi_init() and install
 * the new EFI memory map that we are about to pass to the
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 844d31cb8a0c..36b0b042ba56 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -654,3 +654,51 @@ int efi_capsule_setup_info(struct capsule_info *cap_info, 
void *kbuff,
 }
 
 #endif
+
+#ifdef CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS
+
+static bool original_memory_map_present;
+static struct efi_memory_map original_memory_map;
+
+/*
+ * The efi page fault handler that recovers from page faults caused by
+ * buggy firmware needs original memory map passed by firmware. Hence,
+ * build a new EFI memmap that has all entries and save it for later use.
+ */
+void __init efi_save_original_memmap(void)
+{
+   efi_memory_desc_t *md;
+   void *remapped_phys, *new_md;
+   phys_addr_t new_phys, new_size;
+
+   new_size = efi.memmap.desc_size * efi.memmap.nr_map;
+   new_phys = efi_memmap_alloc(efi.memmap.nr_map);
+   if (!new_phys) {
+   pr_err("Failed to allocate new EFI memmap\n");
+   return;
+   }
+
+   remapped_phys = memremap(new_phys, new_size, MEMREMAP_WB);
+   if (!remapped_phys) {
+   pr_err("Failed to remap new EFI memmap\n");
+   __free_pages(pfn_to_page(PHYS_PFN(new_phys)), 
get_order(new_size));
+   return;
+   }
+
+   new_md = remapped_phys;
+   for_each_efi_memory_desc(md) {
+   memcpy(new_md, md, efi.memmap.desc_size);
+   new_md += efi.memmap.desc_size;
+   }
+
+   original_memory_map.late = 1;
+   original_memory_map.phys_map = new_phys;
+   original_memory_map.map = remapped_phys;
+   original_memory_map.nr_map = efi.memmap.nr_map;
+   original_memory_map.desc_size = efi.memmap.desc_size;
+   original_memory_map.map_end = remapped_phys + new_size;
+   original_memory_map.desc_version = efi.memmap.desc_version;
+
+   original_memory_map_present = true;
+}
+#endif /* CONFIG_EFI_WARN_ON_ILLEGAL_ACCESS */
-- 
2.7.4