public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* Conflicting virtual addresses causing Runtime Services issues
@ 2021-03-10  8:04 Jon Nettleton
  2021-03-10 14:52 ` [edk2-devel] " Laszlo Ersek
  0 siblings, 1 reply; 13+ messages in thread
From: Jon Nettleton @ 2021-03-10  8:04 UTC (permalink / raw)
  To: devel

I am debugging a failure that I am seeing while using the HoneyComb's
spi-nor flash for runtime variable storage.  I am hoping someone on
the list can give me some insight as what may be the problem.

The problem showed up when we switched the MMIO region for the fspi
flash device to be marked as non executable.  reading variables is
fine, however writes began throwing an error.

[  556.709828] Unable to handle kernel execute from non-executable
memory at virtual address 00000000206a3968

I have patched the kernel and removed the X86 requirement and enabled
the sysfs runtime mappings kernel config so I can get an easy view of
the mappings the kernel carries for runtime services.  I then track
that virtual address to the MMIO region of nor flash, which makes
sense that region is marked as non executable.  The question is why is
code being executed from this address range

attribute
::::::::::::::
0x8000000000000001
::::::::::::::
num_pages
::::::::::::::
0x40
::::::::::::::
phys_addr
::::::::::::::
0x20500000
::::::::::::::
type
::::::::::::::
0xb
::::::::::::::
virt_addr
::::::::::::::
0x20680000

So then I patched the PL011 serial driver to be able to log to the
console in runtime and I track down the access to Status =
Fvb->GetPhysicalAddress(Fvb, &FvVolHdr); in UpdateVariableStore().
What I don't understand is why EfiConvertPointer is mapping that
pointer into the Virtual address space occupied by the runtime mmio of
the flash.  The pointer is being properly remapped.  Here are the
pointer addresses in EFI and Kernel Runtime

EFI:
UpdateVariableStore:156 ECE33968
FvbGetPhysicalAddress(BaseAddress=0x20000000)

KERNEL:
UpdateVariableStore:156 206A3968
[  556.709828] Unable to handle kernel execute from non-executable
memory at virtual address 00000000206a3968

Any insight that anyone could provide would be much appreciated.

Thanks,
Jon

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
  2021-03-10  8:04 Conflicting virtual addresses causing Runtime Services issues Jon Nettleton
@ 2021-03-10 14:52 ` Laszlo Ersek
  2021-03-11  6:53   ` Jon Nettleton
       [not found]   ` <166B374585A9D8FC.18699@groups.io>
  0 siblings, 2 replies; 13+ messages in thread
From: Laszlo Ersek @ 2021-03-10 14:52 UTC (permalink / raw)
  To: devel, jon

On 03/10/21 09:04, Jon Nettleton wrote:
> I am debugging a failure that I am seeing while using the HoneyComb's
> spi-nor flash for runtime variable storage.  I am hoping someone on
> the list can give me some insight as what may be the problem.
> 
> The problem showed up when we switched the MMIO region for the fspi
> flash device to be marked as non executable.  reading variables is
> fine, however writes began throwing an error.
> 
> [  556.709828] Unable to handle kernel execute from non-executable
> memory at virtual address 00000000206a3968
> 
> I have patched the kernel and removed the X86 requirement and enabled
> the sysfs runtime mappings kernel config so I can get an easy view of
> the mappings the kernel carries for runtime services.  I then track
> that virtual address to the MMIO region of nor flash, which makes
> sense that region is marked as non executable.  The question is why is
> code being executed from this address range
> 
> attribute
> ::::::::::::::
> 0x8000000000000001
> ::::::::::::::
> num_pages
> ::::::::::::::
> 0x40
> ::::::::::::::
> phys_addr
> ::::::::::::::
> 0x20500000
> ::::::::::::::
> type
> ::::::::::::::
> 0xb
> ::::::::::::::
> virt_addr
> ::::::::::::::
> 0x20680000
> 
> So then I patched the PL011 serial driver to be able to log to the
> console in runtime and I track down the access to Status =
> Fvb->GetPhysicalAddress(Fvb, &FvVolHdr); in UpdateVariableStore().
> What I don't understand is why EfiConvertPointer is mapping that
> pointer into the Virtual address space occupied by the runtime mmio of
> the flash.  The pointer is being properly remapped.  Here are the
> pointer addresses in EFI and Kernel Runtime
> 
> EFI:
> UpdateVariableStore:156 ECE33968
> FvbGetPhysicalAddress(BaseAddress=0x20000000)
> 
> KERNEL:
> UpdateVariableStore:156 206A3968
> [  556.709828] Unable to handle kernel execute from non-executable
> memory at virtual address 00000000206a3968
> 
> Any insight that anyone could provide would be much appreciated.

Your platform appears misconfigured -- the flash MMIO range appears to
overlap runtime services code even before SetVirtualAddressMap. The
virtual address conflict is likely the result of the original physical
address conflict.

After the virtual address updates, the EfiMemoryMappedIO (0xb) type
range is mapped at virtual address range [0x20680000, 0x206C0000). The
GetPhysicalAddress function seems to be located at offset 0x23968 in
that range (with 0x1C698 bytes to go in the range). That's inexplicable.

What is the physical base address of the flash? What are the PCDs used
in "ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvb.c"?

Laszlo


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
  2021-03-10 14:52 ` [edk2-devel] " Laszlo Ersek
@ 2021-03-11  6:53   ` Jon Nettleton
       [not found]   ` <166B374585A9D8FC.18699@groups.io>
  1 sibling, 0 replies; 13+ messages in thread
From: Jon Nettleton @ 2021-03-11  6:53 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: devel

On Wed, Mar 10, 2021 at 3:52 PM Laszlo Ersek <lersek@redhat.com> wrote:
>
> On 03/10/21 09:04, Jon Nettleton wrote:
> > I am debugging a failure that I am seeing while using the HoneyComb's
> > spi-nor flash for runtime variable storage.  I am hoping someone on
> > the list can give me some insight as what may be the problem.
> >
> > The problem showed up when we switched the MMIO region for the fspi
> > flash device to be marked as non executable.  reading variables is
> > fine, however writes began throwing an error.
> >
> > [  556.709828] Unable to handle kernel execute from non-executable
> > memory at virtual address 00000000206a3968
> >
> > I have patched the kernel and removed the X86 requirement and enabled
> > the sysfs runtime mappings kernel config so I can get an easy view of
> > the mappings the kernel carries for runtime services.  I then track
> > that virtual address to the MMIO region of nor flash, which makes
> > sense that region is marked as non executable.  The question is why is
> > code being executed from this address range
> >
> > attribute
> > ::::::::::::::
> > 0x8000000000000001
> > ::::::::::::::
> > num_pages
> > ::::::::::::::
> > 0x40
> > ::::::::::::::
> > phys_addr
> > ::::::::::::::
> > 0x20500000
> > ::::::::::::::
> > type
> > ::::::::::::::
> > 0xb
> > ::::::::::::::
> > virt_addr
> > ::::::::::::::
> > 0x20680000
> >
> > So then I patched the PL011 serial driver to be able to log to the
> > console in runtime and I track down the access to Status =
> > Fvb->GetPhysicalAddress(Fvb, &FvVolHdr); in UpdateVariableStore().
> > What I don't understand is why EfiConvertPointer is mapping that
> > pointer into the Virtual address space occupied by the runtime mmio of
> > the flash.  The pointer is being properly remapped.  Here are the
> > pointer addresses in EFI and Kernel Runtime
> >
> > EFI:
> > UpdateVariableStore:156 ECE33968
> > FvbGetPhysicalAddress(BaseAddress=0x20000000)
> >
> > KERNEL:
> > UpdateVariableStore:156 206A3968
> > [  556.709828] Unable to handle kernel execute from non-executable
> > memory at virtual address 00000000206a3968
> >
> > Any insight that anyone could provide would be much appreciated.
>
> Your platform appears misconfigured -- the flash MMIO range appears to
> overlap runtime services code even before SetVirtualAddressMap. The
> virtual address conflict is likely the result of the original physical
> address conflict.

There is no physical address conflict.  Running in physical mode the pointer
for GetPhysicalAddress is at 0xECE33968 and the MMIO physical
region is 0x20000000 - 0x2FFFFFFF.  Shown as the BaseAddress above.
Obviously I don't use that full MMIO region because our flash is not
256MB.

>
> After the virtual address updates, the EfiMemoryMappedIO (0xb) type
> range is mapped at virtual address range [0x20680000, 0x206C0000). The
> GetPhysicalAddress function seems to be located at offset 0x23968 in
> that range (with 0x1C698 bytes to go in the range). That's inexplicable.

Yes, exactly why I am reaching out.

>
> What is the physical base address of the flash? What are the PCDs used
> in "ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvb.c"?

We don't use the ArmPlatformPkg

The code is available here.
https://github.com/SolidRun/edk2-platforms/tree/LX2160_UEFI_ACPI_EAR3-lx2160cex7/Silicon/NXP/Drivers/SpiNorFlashDxe

Thanks
>
> Laszlo
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
       [not found]   ` <166B374585A9D8FC.18699@groups.io>
@ 2021-03-11  9:48     ` Jon Nettleton
  2021-03-11 14:50       ` Laszlo Ersek
  0 siblings, 1 reply; 13+ messages in thread
From: Jon Nettleton @ 2021-03-11  9:48 UTC (permalink / raw)
  To: devel, Jon Nettleton; +Cc: Laszlo Ersek

On Thu, Mar 11, 2021 at 7:54 AM Jon Nettleton via groups.io
<jon=solid-run.com@groups.io> wrote:
>
> On Wed, Mar 10, 2021 at 3:52 PM Laszlo Ersek <lersek@redhat.com> wrote:
> >
> > On 03/10/21 09:04, Jon Nettleton wrote:
> > > I am debugging a failure that I am seeing while using the HoneyComb's
> > > spi-nor flash for runtime variable storage.  I am hoping someone on
> > > the list can give me some insight as what may be the problem.
> > >
> > > The problem showed up when we switched the MMIO region for the fspi
> > > flash device to be marked as non executable.  reading variables is
> > > fine, however writes began throwing an error.
> > >
> > > [  556.709828] Unable to handle kernel execute from non-executable
> > > memory at virtual address 00000000206a3968
> > >
> > > I have patched the kernel and removed the X86 requirement and enabled
> > > the sysfs runtime mappings kernel config so I can get an easy view of
> > > the mappings the kernel carries for runtime services.  I then track
> > > that virtual address to the MMIO region of nor flash, which makes
> > > sense that region is marked as non executable.  The question is why is
> > > code being executed from this address range
> > >
> > > attribute
> > > ::::::::::::::
> > > 0x8000000000000001
> > > ::::::::::::::
> > > num_pages
> > > ::::::::::::::
> > > 0x40
> > > ::::::::::::::
> > > phys_addr
> > > ::::::::::::::
> > > 0x20500000
> > > ::::::::::::::
> > > type
> > > ::::::::::::::
> > > 0xb
> > > ::::::::::::::
> > > virt_addr
> > > ::::::::::::::
> > > 0x20680000
> > >
> > > So then I patched the PL011 serial driver to be able to log to the
> > > console in runtime and I track down the access to Status =
> > > Fvb->GetPhysicalAddress(Fvb, &FvVolHdr); in UpdateVariableStore().
> > > What I don't understand is why EfiConvertPointer is mapping that
> > > pointer into the Virtual address space occupied by the runtime mmio of
> > > the flash.  The pointer is being properly remapped.  Here are the
> > > pointer addresses in EFI and Kernel Runtime
> > >
> > > EFI:
> > > UpdateVariableStore:156 ECE33968
> > > FvbGetPhysicalAddress(BaseAddress=0x20000000)
> > >
> > > KERNEL:
> > > UpdateVariableStore:156 206A3968
> > > [  556.709828] Unable to handle kernel execute from non-executable
> > > memory at virtual address 00000000206a3968
> > >
> > > Any insight that anyone could provide would be much appreciated.
> >
> > Your platform appears misconfigured -- the flash MMIO range appears to
> > overlap runtime services code even before SetVirtualAddressMap. The
> > virtual address conflict is likely the result of the original physical
> > address conflict.
>
> There is no physical address conflict.  Running in physical mode the pointer
> for GetPhysicalAddress is at 0xECE33968 and the MMIO physical
> region is 0x20000000 - 0x2FFFFFFF.  Shown as the BaseAddress above.
> Obviously I don't use that full MMIO region because our flash is not
> 256MB.
>
> >
> > After the virtual address updates, the EfiMemoryMappedIO (0xb) type
> > range is mapped at virtual address range [0x20680000, 0x206C0000). The
> > GetPhysicalAddress function seems to be located at offset 0x23968 in
> > that range (with 0x1C698 bytes to go in the range). That's inexplicable.
>
> Yes, exactly why I am reaching out.
>
> >
> > What is the physical base address of the flash? What are the PCDs used
> > in "ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvb.c"?
>
> We don't use the ArmPlatformPkg
>
> The code is available here.
> https://github.com/SolidRun/edk2-platforms/tree/LX2160_UEFI_ACPI_EAR3-lx2160cex7/Silicon/NXP/Drivers/SpiNorFlashDxe
>
> Thanks
> >

Found the root of my problem and fixed it.  As used from other devices
they are relocating the individual pointer for each function in FvbProtocol
of the DXE.  This is done in ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvb.c,
as well as lots of vendor drivers.  I was able to dump the addresses being used
in RuntimeDriverConvertPointer and could locate the pointer to
GetPhysicalAddress.

Convert 0xEC8C1648:0xEC8B0000:0x203D0000
New virtual address is then 203E1648 which is fine.

However then later down in the remapping I found
Convert 0x203E1648:0x20000000:0x20800000

And this is where the pointer gets remapped again and into the
MMIO space of the nor flash.  If I remove the calls to
ConvertPointer for the FvbProtocol I am still seeing those addresses
getting remapped but only once and runtime works as expected.

I am seeing that in MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
&mVariableModuleGlobal->FvbInstance->* are all being converted.  It is
possible this is a long standing bug and it just so happens that our
configuration
has caused a conflict and exposed it.

-Jon

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
  2021-03-11  9:48     ` Jon Nettleton
@ 2021-03-11 14:50       ` Laszlo Ersek
  2021-03-11 15:49         ` Jon Nettleton
  2021-03-11 22:25         ` Laszlo Ersek
  0 siblings, 2 replies; 13+ messages in thread
From: Laszlo Ersek @ 2021-03-11 14:50 UTC (permalink / raw)
  To: devel, jon; +Cc: Hao A Wu, Liming Gao

On 03/11/21 10:48, Jon Nettleton wrote:
> On Thu, Mar 11, 2021 at 7:54 AM Jon Nettleton via groups.io
> <jon=solid-run.com@groups.io> wrote:
>>
>> On Wed, Mar 10, 2021 at 3:52 PM Laszlo Ersek <lersek@redhat.com> wrote:
>>>
>>> On 03/10/21 09:04, Jon Nettleton wrote:
>>>> I am debugging a failure that I am seeing while using the HoneyComb's
>>>> spi-nor flash for runtime variable storage.  I am hoping someone on
>>>> the list can give me some insight as what may be the problem.
>>>>
>>>> The problem showed up when we switched the MMIO region for the fspi
>>>> flash device to be marked as non executable.  reading variables is
>>>> fine, however writes began throwing an error.
>>>>
>>>> [  556.709828] Unable to handle kernel execute from non-executable
>>>> memory at virtual address 00000000206a3968
>>>>
>>>> I have patched the kernel and removed the X86 requirement and enabled
>>>> the sysfs runtime mappings kernel config so I can get an easy view of
>>>> the mappings the kernel carries for runtime services.  I then track
>>>> that virtual address to the MMIO region of nor flash, which makes
>>>> sense that region is marked as non executable.  The question is why is
>>>> code being executed from this address range
>>>>
>>>> attribute
>>>> ::::::::::::::
>>>> 0x8000000000000001
>>>> ::::::::::::::
>>>> num_pages
>>>> ::::::::::::::
>>>> 0x40
>>>> ::::::::::::::
>>>> phys_addr
>>>> ::::::::::::::
>>>> 0x20500000
>>>> ::::::::::::::
>>>> type
>>>> ::::::::::::::
>>>> 0xb
>>>> ::::::::::::::
>>>> virt_addr
>>>> ::::::::::::::
>>>> 0x20680000
>>>>
>>>> So then I patched the PL011 serial driver to be able to log to the
>>>> console in runtime and I track down the access to Status =
>>>> Fvb->GetPhysicalAddress(Fvb, &FvVolHdr); in UpdateVariableStore().
>>>> What I don't understand is why EfiConvertPointer is mapping that
>>>> pointer into the Virtual address space occupied by the runtime mmio of
>>>> the flash.  The pointer is being properly remapped.  Here are the
>>>> pointer addresses in EFI and Kernel Runtime
>>>>
>>>> EFI:
>>>> UpdateVariableStore:156 ECE33968
>>>> FvbGetPhysicalAddress(BaseAddress=0x20000000)
>>>>
>>>> KERNEL:
>>>> UpdateVariableStore:156 206A3968
>>>> [  556.709828] Unable to handle kernel execute from non-executable
>>>> memory at virtual address 00000000206a3968
>>>>
>>>> Any insight that anyone could provide would be much appreciated.
>>>
>>> Your platform appears misconfigured -- the flash MMIO range appears to
>>> overlap runtime services code even before SetVirtualAddressMap. The
>>> virtual address conflict is likely the result of the original physical
>>> address conflict.
>>
>> There is no physical address conflict.  Running in physical mode the pointer
>> for GetPhysicalAddress is at 0xECE33968 and the MMIO physical
>> region is 0x20000000 - 0x2FFFFFFF.  Shown as the BaseAddress above.
>> Obviously I don't use that full MMIO region because our flash is not
>> 256MB.
>>
>>>
>>> After the virtual address updates, the EfiMemoryMappedIO (0xb) type
>>> range is mapped at virtual address range [0x20680000, 0x206C0000). The
>>> GetPhysicalAddress function seems to be located at offset 0x23968 in
>>> that range (with 0x1C698 bytes to go in the range). That's inexplicable.
>>
>> Yes, exactly why I am reaching out.
>>
>>>
>>> What is the physical base address of the flash? What are the PCDs used
>>> in "ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvb.c"?
>>
>> We don't use the ArmPlatformPkg
>>
>> The code is available here.
>> https://github.com/SolidRun/edk2-platforms/tree/LX2160_UEFI_ACPI_EAR3-lx2160cex7/Silicon/NXP/Drivers/SpiNorFlashDxe
>>
>> Thanks
>>>
> 
> Found the root of my problem and fixed it.  As used from other devices
> they are relocating the individual pointer for each function in FvbProtocol
> of the DXE.  This is done in ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvb.c,
> as well as lots of vendor drivers.  I was able to dump the addresses being used
> in RuntimeDriverConvertPointer and could locate the pointer to
> GetPhysicalAddress.
> 
> Convert 0xEC8C1648:0xEC8B0000:0x203D0000
> New virtual address is then 203E1648 which is fine.
> 
> However then later down in the remapping I found
> Convert 0x203E1648:0x20000000:0x20800000
> 
> And this is where the pointer gets remapped again and into the
> MMIO space of the nor flash.  If I remove the calls to
> ConvertPointer for the FvbProtocol I am still seeing those addresses
> getting remapped but only once and runtime works as expected.
> 
> I am seeing that in MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> &mVariableModuleGlobal->FvbInstance->* are all being converted.  It is
> possible this is a long standing bug and it just so happens that our
> configuration
> has caused a conflict and exposed it.

Yes, this is curious, I noticed it too yesterday, trying to see where
the FVB protocol member function pointers were converted. I found that
OVMF's flash driver (OvmfPkg/QemuFlashFvbServicesRuntimeDxe) didn't do
it, but MdeModulePkg/Universal/Variable/RuntimeDxe did. That was
certainly strange, as the variable driver is a consumer of the protocol
(not the producer thereof), so I'd say it has no business poking new
values into the protocol interface structure.

So the issue (IIUC) on your platform is that the function pointers are
doubly-converted, once by your flash driver (which is arguably the right
thing), and another time by the variable driver.

I recommend filing a bug about this, at
<https://bugzilla.tianocore.org/>, against "VariableDxe.c".

I suggest CC'ing the "UEFI Variable modules" reviewers on the BZ as
well, from "Maintainers.txt" -- FWIW, I'm CC'ing Hao and Liming on this
email, now.

... It feels as if the Platform Init specification should speak to the
FVB[2] protocol's runtime aspects... But (as of v1.7), I don't see
anything runtime-related in that section. In fact I've checked the whole
PI v1.7 spec for "runtime", and the closest matches are under
EFI_VARIABLE_WRITE_ARCH_PROTOCOL. FVB2 is not spelled out as a
(potential) runtime dependency of EFI_VARIABLE_WRITE_ARCH_PROTOCOL. The
only explicitly runtime protocol (unrelated to runtime services) is
"Status Code Runtime Protocol".

So what we're seeing here is an edk2-ism, I believe.

I tried seeing if one of the "tour beyond BIOS" edk2 whitepapers said
anything on FVB -- but the only reference I found (in "Implementing
UEFI Authenticated Variables in SMM with EDKII", version 2) mentions
only *SMM* FVB.

https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-white-papers

I think we should have a TianoCore BZ about this, even if we don' change
the code as a result -- which driver is responsible for updating the
runtime FVB protocol member functions should be spelled out somewhere
"searchable".

... Strangely, the other flash (FVB) driver in edk2,
ArmPlatformPkg/Drivers/NorFlashDxe, *does* perform the conversion
itself! See NorFlashVirtualNotifyEvent().

I don't understand that. Is it possible that, with
"ArmPlatformPkg/Drivers/NorFlashDxe" too, the conversion happens
*twice*, but (at least) one of those mappings is "identity"?

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
  2021-03-11 14:50       ` Laszlo Ersek
@ 2021-03-11 15:49         ` Jon Nettleton
  2021-03-11 22:25         ` Laszlo Ersek
  1 sibling, 0 replies; 13+ messages in thread
From: Jon Nettleton @ 2021-03-11 15:49 UTC (permalink / raw)
  To: devel, Laszlo Ersek; +Cc: Hao A Wu, Liming Gao

On Thu, Mar 11, 2021 at 3:51 PM Laszlo Ersek <lersek@redhat.com> wrote:
>
> On 03/11/21 10:48, Jon Nettleton wrote:
> > On Thu, Mar 11, 2021 at 7:54 AM Jon Nettleton via groups.io
> > <jon=solid-run.com@groups.io> wrote:
> >>
> >> On Wed, Mar 10, 2021 at 3:52 PM Laszlo Ersek <lersek@redhat.com> wrote:
> >>>
> >>> On 03/10/21 09:04, Jon Nettleton wrote:
> >>>> I am debugging a failure that I am seeing while using the HoneyComb's
> >>>> spi-nor flash for runtime variable storage.  I am hoping someone on
> >>>> the list can give me some insight as what may be the problem.
> >>>>
> >>>> The problem showed up when we switched the MMIO region for the fspi
> >>>> flash device to be marked as non executable.  reading variables is
> >>>> fine, however writes began throwing an error.
> >>>>
> >>>> [  556.709828] Unable to handle kernel execute from non-executable
> >>>> memory at virtual address 00000000206a3968
> >>>>
> >>>> I have patched the kernel and removed the X86 requirement and enabled
> >>>> the sysfs runtime mappings kernel config so I can get an easy view of
> >>>> the mappings the kernel carries for runtime services.  I then track
> >>>> that virtual address to the MMIO region of nor flash, which makes
> >>>> sense that region is marked as non executable.  The question is why is
> >>>> code being executed from this address range
> >>>>
> >>>> attribute
> >>>> ::::::::::::::
> >>>> 0x8000000000000001
> >>>> ::::::::::::::
> >>>> num_pages
> >>>> ::::::::::::::
> >>>> 0x40
> >>>> ::::::::::::::
> >>>> phys_addr
> >>>> ::::::::::::::
> >>>> 0x20500000
> >>>> ::::::::::::::
> >>>> type
> >>>> ::::::::::::::
> >>>> 0xb
> >>>> ::::::::::::::
> >>>> virt_addr
> >>>> ::::::::::::::
> >>>> 0x20680000
> >>>>
> >>>> So then I patched the PL011 serial driver to be able to log to the
> >>>> console in runtime and I track down the access to Status =
> >>>> Fvb->GetPhysicalAddress(Fvb, &FvVolHdr); in UpdateVariableStore().
> >>>> What I don't understand is why EfiConvertPointer is mapping that
> >>>> pointer into the Virtual address space occupied by the runtime mmio of
> >>>> the flash.  The pointer is being properly remapped.  Here are the
> >>>> pointer addresses in EFI and Kernel Runtime
> >>>>
> >>>> EFI:
> >>>> UpdateVariableStore:156 ECE33968
> >>>> FvbGetPhysicalAddress(BaseAddress=0x20000000)
> >>>>
> >>>> KERNEL:
> >>>> UpdateVariableStore:156 206A3968
> >>>> [  556.709828] Unable to handle kernel execute from non-executable
> >>>> memory at virtual address 00000000206a3968
> >>>>
> >>>> Any insight that anyone could provide would be much appreciated.
> >>>
> >>> Your platform appears misconfigured -- the flash MMIO range appears to
> >>> overlap runtime services code even before SetVirtualAddressMap. The
> >>> virtual address conflict is likely the result of the original physical
> >>> address conflict.
> >>
> >> There is no physical address conflict.  Running in physical mode the pointer
> >> for GetPhysicalAddress is at 0xECE33968 and the MMIO physical
> >> region is 0x20000000 - 0x2FFFFFFF.  Shown as the BaseAddress above.
> >> Obviously I don't use that full MMIO region because our flash is not
> >> 256MB.
> >>
> >>>
> >>> After the virtual address updates, the EfiMemoryMappedIO (0xb) type
> >>> range is mapped at virtual address range [0x20680000, 0x206C0000). The
> >>> GetPhysicalAddress function seems to be located at offset 0x23968 in
> >>> that range (with 0x1C698 bytes to go in the range). That's inexplicable.
> >>
> >> Yes, exactly why I am reaching out.
> >>
> >>>
> >>> What is the physical base address of the flash? What are the PCDs used
> >>> in "ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvb.c"?
> >>
> >> We don't use the ArmPlatformPkg
> >>
> >> The code is available here.
> >> https://github.com/SolidRun/edk2-platforms/tree/LX2160_UEFI_ACPI_EAR3-lx2160cex7/Silicon/NXP/Drivers/SpiNorFlashDxe
> >>
> >> Thanks
> >>>
> >
> > Found the root of my problem and fixed it.  As used from other devices
> > they are relocating the individual pointer for each function in FvbProtocol
> > of the DXE.  This is done in ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvb.c,
> > as well as lots of vendor drivers.  I was able to dump the addresses being used
> > in RuntimeDriverConvertPointer and could locate the pointer to
> > GetPhysicalAddress.
> >
> > Convert 0xEC8C1648:0xEC8B0000:0x203D0000
> > New virtual address is then 203E1648 which is fine.
> >
> > However then later down in the remapping I found
> > Convert 0x203E1648:0x20000000:0x20800000
> >
> > And this is where the pointer gets remapped again and into the
> > MMIO space of the nor flash.  If I remove the calls to
> > ConvertPointer for the FvbProtocol I am still seeing those addresses
> > getting remapped but only once and runtime works as expected.
> >
> > I am seeing that in MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> > &mVariableModuleGlobal->FvbInstance->* are all being converted.  It is
> > possible this is a long standing bug and it just so happens that our
> > configuration
> > has caused a conflict and exposed it.
>
> Yes, this is curious, I noticed it too yesterday, trying to see where
> the FVB protocol member function pointers were converted. I found that
> OVMF's flash driver (OvmfPkg/QemuFlashFvbServicesRuntimeDxe) didn't do
> it, but MdeModulePkg/Universal/Variable/RuntimeDxe did. That was
> certainly strange, as the variable driver is a consumer of the protocol
> (not the producer thereof), so I'd say it has no business poking new
> values into the protocol interface structure.
>
> So the issue (IIUC) on your platform is that the function pointers are
> doubly-converted, once by your flash driver (which is arguably the right
> thing), and another time by the variable driver.

Correct, that seems to be what is happening

>
> I recommend filing a bug about this, at
> <https://bugzilla.tianocore.org/>, against "VariableDxe.c".

Sure

>
> I suggest CC'ing the "UEFI Variable modules" reviewers on the BZ as
> well, from "Maintainers.txt" -- FWIW, I'm CC'ing Hao and Liming on this
> email, now.
>
> ... It feels as if the Platform Init specification should speak to the
> FVB[2] protocol's runtime aspects... But (as of v1.7), I don't see
> anything runtime-related in that section. In fact I've checked the whole
> PI v1.7 spec for "runtime", and the closest matches are under
> EFI_VARIABLE_WRITE_ARCH_PROTOCOL. FVB2 is not spelled out as a
> (potential) runtime dependency of EFI_VARIABLE_WRITE_ARCH_PROTOCOL. The
> only explicitly runtime protocol (unrelated to runtime services) is
> "Status Code Runtime Protocol".
>
> So what we're seeing here is an edk2-ism, I believe.

I checked the commits and the code that does that conversion is quite old.

>
> I tried seeing if one of the "tour beyond BIOS" edk2 whitepapers said
> anything on FVB -- but the only reference I found (in "Implementing
> UEFI Authenticated Variables in SMM with EDKII", version 2) mentions
> only *SMM* FVB.
>
> https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-white-papers
>
> I think we should have a TianoCore BZ about this, even if we don' change
> the code as a result -- which driver is responsible for updating the
> runtime FVB protocol member functions should be spelled out somewhere
> "searchable".
>
> ... Strangely, the other flash (FVB) driver in edk2,
> ArmPlatformPkg/Drivers/NorFlashDxe, *does* perform the conversion
> itself! See NorFlashVirtualNotifyEvent().
>
> I don't understand that. Is it possible that, with
> "ArmPlatformPkg/Drivers/NorFlashDxe" too, the conversion happens
> *twice*, but (at least) one of those mappings is "identity"?

I believe all the drivers that are doing the conversion are getting
double mappings.  It just so happens our second mapping got poked
into an area that we had marked non-executable which started the
debugging and led to the issue.

>
> Thanks
> Laszlo
>
>
>
> 
>
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
  2021-03-11 14:50       ` Laszlo Ersek
  2021-03-11 15:49         ` Jon Nettleton
@ 2021-03-11 22:25         ` Laszlo Ersek
  2021-03-11 22:39           ` Ard Biesheuvel
  1 sibling, 1 reply; 13+ messages in thread
From: Laszlo Ersek @ 2021-03-11 22:25 UTC (permalink / raw)
  To: devel, jon
  Cc: Hao A Wu, Liming Gao, Ard Biesheuvel (TianoCore),
	Leif Lindholm (Nuvia address)

[-- Attachment #1: Type: text/plain, Size: 7335 bytes --]

Adding Ard and Leif, comments below:

On 03/11/21 15:50, Laszlo Ersek wrote:
> On 03/11/21 10:48, Jon Nettleton wrote:

[...]

>> And this is where the pointer gets remapped again and into the MMIO
>> space of the nor flash.  If I remove the calls to ConvertPointer for
>> the FvbProtocol I am still seeing those addresses getting remapped
>> but only once and runtime works as expected.
>>
>> I am seeing that in
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
>> &mVariableModuleGlobal->FvbInstance->* are all being converted.  It
>> is possible this is a long standing bug and it just so happens that
>> our configuration has caused a conflict and exposed it.
>
> Yes, this is curious, I noticed it too yesterday, trying to see where
> the FVB protocol member function pointers were converted. I found that
> OVMF's flash driver (OvmfPkg/QemuFlashFvbServicesRuntimeDxe) didn't do
> it, but MdeModulePkg/Universal/Variable/RuntimeDxe did. That was
> certainly strange, as the variable driver is a consumer of the
> protocol (not the producer thereof), so I'd say it has no business
> poking new values into the protocol interface structure.

[...]

> ... Strangely, the other flash (FVB) driver in edk2,
> ArmPlatformPkg/Drivers/NorFlashDxe, *does* perform the conversion
> itself! See NorFlashVirtualNotifyEvent().
>
> I don't understand that. Is it possible that, with
> "ArmPlatformPkg/Drivers/NorFlashDxe" too, the conversion happens
> *twice*, but (at least) one of those mappings is "identity"?

Confirmed.

I had to write some elaborate debug patches for determining this,
because in ArmVirtQemu, I cannot produce DEBUG output from the
SetVirtualAddressMap() notification functions. So here's the approach I
took:

(1) Introduce a new GUID-ed HOB structure in MdeModulePkg. The structure
itself lives in reserved memory, but its address is exposed in a GUID-ed
HOB. The structure is named FVB_ADDRESS_LIST, and it has the following
fields:

  - signature ("FVBADRLS" -- FVB Address List)
  - 16 entries of:
    - owner signature [what driver set this entry]
    - address
  - number of entries used (aka next entry to fill)

(2) In PlatformPei, allocate and initialize this structure (in reserved
memory), and expose its address via the GUID-ed HOB. Furthermore,
produce a log message with the allocation address.

(3) In NorFlashDxe, look up the structure via the GUID-ed HOB, in the
entry point function; remember the address in a global variable. In the
SetVirtualAddressMap() handler function, treat the conversion of the
"GetPhysicalAddress" FVB member function specially: via the global
variable pointer to FVB_ADDRESS_LIST in reserved memory, save both the
physical (original) and the virtual (converted) address of the
"GetPhysicalAddress" FVB member function, in new entries. As owner
signature in both entries, use "NORFLASH".

(4) In the runtime DXE variable driver, do the exact same thing, just
use a different "owner signature" -- "VARIABLE".

(5) Once the guest is up and running, run "efibootmgr --delete-timeout"
at a root prompt in the guest, deleting the existent "Timeout" UEFI
non-volatile variable, for verifying that the runtime variable (write)
service is functional.

(6) Using the log message from point (2):

> PlatformPeim: FvbAddressList @ 13FEC9000

hexdump the guest memory containing the FVB_ADDRESS_LIST, as follows:

> $ virsh qemu-monitor-command aavmf.rhel7.registered --hmp xp  /268cb 0x13FEC9000

Ccomments to the right of the hexdump:

> 000000013fec9000: 'F' 'V' 'B' 'A' 'D' 'R' 'L' 'S'                         <- structure signature: FVBADRLS
> 000000013fec9008: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[0], signature: NORFLASH
> 000000013fec9010: 'T' ' ' '\xc6' ';' '\x01' '\x00' '\x00' '\x00'          <- entry[0], GetPhysicalAddress *physical*: 0x000000013bc62054
> 000000013fec9018: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[1], signature: NORFLASH
> 000000013fec9020: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[1], GetPhysicalAddress *virtual*: 0x00000000244e2054
> 000000013fec9028: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[2], signature: VARIABLE
> 000000013fec9030: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[2], GetPhysicalAddress *physical*: 0x00000000244e2054
> 000000013fec9038: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[3], signature: VARIABLE
> 000000013fec9040: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[3], GetPhysicalAddress *virtual*: 0x00000000244e2054
> 000000013fec9048: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9050: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9058: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9060: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9068: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9070: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9078: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9080: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9088: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9090: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9098: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90a0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90a8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90b0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90b8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90c0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90c8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90d0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90d8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90e0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90e8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90f0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec90f8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9100: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> 000000013fec9108: '\x04' '\x00' '\x00' '\x00'                             <- number of entries used: 4

This shows the following:

- both NorFlashDxe and the runtime DXE variable driver converted the
  FVB.GetPhysicalAddress member function,

- the NorFlashDxe driver acted first, the runtime DXE variable driver
  acted second,

- when the runtime DXE variable driver "converted" the "physical"
  address to virtual address, there was no change (and no crash!),
  because the virtual address map passed in by the Linux kernel
  apparently identity maps this area -- just as I guessed.

So we definitely have a bug (only Linux's page tables save us from the
crash); now the question is:

Which driver is wrong to even attempt the conversion of the FVB member
functions?

The answer must be documented somewhere highly visible.

Debug patches attached, for the record (based on commit edd46cd407ea).

Thanks
Laszlo

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-MdeModulePkg-Guid-introduce-FVB_ADDRESS_LIST.patch --]
[-- Type: text/x-patch; name="0001-MdeModulePkg-Guid-introduce-FVB_ADDRESS_LIST.patch", Size: 3391 bytes --]

From 6670b74f94dca9dcdcfdcabc370527c735bb152d Mon Sep 17 00:00:00 2001
From: Laszlo Ersek <lersek@redhat.com>
Date: Thu, 11 Mar 2021 21:08:09 +0100
Subject: [PATCH 1/4] MdeModulePkg/Guid: introduce FVB_ADDRESS_LIST

Introduce a new GUIDed HOB. The GUIDed HOB contains a 64-bit physical
address (FVB_ADDRESS_LIST_PTR), pointing to FVB_ADDRESS_LIST.
FVB_ADDRESS_LIST itself lives in reserved memory, and drivers can populate
it with up to 16 FVB-related addresses (64-bit words).

This will be used to stash the original (physical) and converted (virtual)
addresses of some FVB member functions, for guest memory dumping and
debugging purposes.

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 MdeModulePkg/MdeModulePkg.dec              |  3 ++
 MdeModulePkg/Include/Guid/FvbAddressList.h | 45 ++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index f1144144be14..a67f4e8eb92c 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -400,14 +400,17 @@ [Guids]
 
   ## GUID indicates the capsule is to store Capsule On Disk file names.
   gEdkiiCapsuleOnDiskNameGuid = { 0x98c80a4f, 0xe16b, 0x4d11, { 0x93, 0x9a, 0xab, 0xe5, 0x61, 0x26, 0x3, 0x30 } }
 
   ## Include/Guid/MigratedFvInfo.h
   gEdkiiMigratedFvInfoGuid = { 0xc1ab12f7, 0x74aa, 0x408d, { 0xa2, 0xf4, 0xc6, 0xce, 0xfd, 0x17, 0x98, 0x71 } }
 
+  ## Include/Guid/FvbAddressList.h
+  gEdkiiFvbAddressListGuid = { 0xaa87bf00, 0x7f76, 0x4e32, { 0xb3, 0x92, 0x86, 0xa1, 0x3e, 0x37, 0x33, 0x11 } }
+
 [Ppis]
   ## Include/Ppi/AtaController.h
   gPeiAtaControllerPpiGuid       = { 0xa45e60d1, 0xc719, 0x44aa, { 0xb0, 0x7a, 0xaa, 0x77, 0x7f, 0x85, 0x90, 0x6d }}
 
   ## Include/Ppi/UsbHostController.h
   gPeiUsbHostControllerPpiGuid   = { 0x652B38A9, 0x77F4, 0x453F, { 0x89, 0xD5, 0xE7, 0xBD, 0xC3, 0x52, 0xFC, 0x53 }}
 
diff --git a/MdeModulePkg/Include/Guid/FvbAddressList.h b/MdeModulePkg/Include/Guid/FvbAddressList.h
new file mode 100644
index 000000000000..92aa781383f5
--- /dev/null
+++ b/MdeModulePkg/Include/Guid/FvbAddressList.h
@@ -0,0 +1,45 @@
+/** @file
+  Stash FVB-related addresses in a reserved memory structure, pointed-to by a
+  pointer living in a GUID-ed HOB.
+
+  Copyright (C) 2021 Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef FVB_ADDRESS_LIST_H_
+#define FVB_ADDRESS_LIST_H_
+
+#define EDKII_FVB_ADDRESS_LIST_GUID                    \
+  {                                                    \
+    0xaa87bf00,                                        \
+    0x7f76,                                            \
+    0x4e32,                                            \
+    { 0xb3, 0x92, 0x86, 0xa1, 0x3e, 0x37, 0x33, 0x11 } \
+  }
+
+#define FVB_ADDRESS_LIST_SIGNATURE \
+  SIGNATURE_64 ('F', 'V', 'B', 'A', 'D', 'R', 'L', 'S')
+
+typedef struct {
+  UINT64 OwnerSignature;
+  UINT64 Address;
+} FVB_ADDRESS_LIST_ENTRY;
+
+//
+// lives in reserved memory
+//
+typedef struct {
+  UINT64                 Signature;
+  FVB_ADDRESS_LIST_ENTRY Entry[16];
+  UINT32                 Next;
+} FVB_ADDRESS_LIST;
+
+//
+// HOB contents: a pointer to FVB_ADDRESS_LIST
+//
+typedef UINT64 FVB_ADDRESS_LIST_PTR;
+
+extern EFI_GUID gEdkiiFvbAddressListGuid;
+
+#endif // FVB_ADDRESS_LIST_H_
-- 
2.19.1.3.g30247aa5d201


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-ArmVirtPkg-PlatformPeiLib-create-FVB_ADDRESS_LIST.patch --]
[-- Type: text/x-patch; name="0002-ArmVirtPkg-PlatformPeiLib-create-FVB_ADDRESS_LIST.patch", Size: 4986 bytes --]

From d61bf620beb379097eca2705e0cf135f941f13bd Mon Sep 17 00:00:00 2001
From: Laszlo Ersek <lersek@redhat.com>
Date: Thu, 11 Mar 2021 21:35:55 +0100
Subject: [PATCH 2/4] ArmVirtPkg/PlatformPeiLib: create FVB_ADDRESS_LIST

Allocate and initialize FVB_ADDRESS_LIST in a new reserved memory page,
and expose the address in the EDKII_FVB_ADDRESS_LIST_GUID HOB.

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.inf |  2 +
 ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c   | 58 +++++++++++++-------
 2 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.inf b/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.inf
index 3f97ef080520..78eef962fdac 100644
--- a/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.inf
+++ b/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.inf
@@ -27,14 +27,15 @@ [Packages]
   OvmfPkg/OvmfPkg.dec
   SecurityPkg/SecurityPkg.dec
 
 [FeaturePcd]
   gArmVirtTokenSpaceGuid.PcdTpm2SupportEnabled
 
 [LibraryClasses]
+  BaseMemoryLib
   DebugLib
   HobLib
   FdtLib
   PcdLib
   PeiServicesLib
 
 [FixedPcd]
@@ -48,11 +49,12 @@ [Pcd]
 
 [Ppis]
   gOvmfTpmDiscoveredPpiGuid                               ## SOMETIMES_PRODUCES
   gPeiTpmInitializationDonePpiGuid                        ## SOMETIMES_PRODUCES
 
 [Guids]
   gEarlyPL011BaseAddressGuid
+  gEdkiiFvbAddressListGuid
   gFdtHobGuid
 
 [Depex]
   gEfiPeiMemoryDiscoveredPpiGuid
diff --git a/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c b/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c
index 6c4028e17995..079ecfad336d 100644
--- a/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c
+++ b/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c
@@ -5,14 +5,16 @@
 *
 *  SPDX-License-Identifier: BSD-2-Clause-Patent
 *
 **/
 
 #include <PiPei.h>
 
+#include <Guid/FvbAddressList.h>
+#include <Library/BaseMemoryLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/DebugLib.h>
 #include <Library/HobLib.h>
 #include <Library/PcdLib.h>
 #include <Library/PeiServicesLib.h>
 #include <libfdt.h>
 
@@ -33,33 +35,35 @@ STATIC CONST EFI_PEI_PPI_DESCRIPTOR mTpm2InitializationDonePpi = {
 
 EFI_STATUS
 EFIAPI
 PlatformPeim (
   VOID
   )
 {
-  VOID               *Base;
-  VOID               *NewBase;
-  UINTN              FdtSize;
-  UINTN              FdtPages;
-  UINT64             *FdtHobData;
-  UINT64             *UartHobData;
-  INT32              Node, Prev;
-  INT32              Parent, Depth;
-  CONST CHAR8        *Compatible;
-  CONST CHAR8        *CompItem;
-  CONST CHAR8        *NodeStatus;
-  INT32              Len;
-  INT32              RangesLen;
-  INT32              StatusLen;
-  CONST UINT64       *RegProp;
-  CONST UINT32       *RangesProp;
-  UINT64             UartBase;
-  UINT64             TpmBase;
-  EFI_STATUS         Status;
+  VOID                 *Base;
+  VOID                 *NewBase;
+  UINTN                FdtSize;
+  UINTN                FdtPages;
+  UINT64               *FdtHobData;
+  UINT64               *UartHobData;
+  INT32                Node, Prev;
+  INT32                Parent, Depth;
+  CONST CHAR8          *Compatible;
+  CONST CHAR8          *CompItem;
+  CONST CHAR8          *NodeStatus;
+  INT32                Len;
+  INT32                RangesLen;
+  INT32                StatusLen;
+  CONST UINT64         *RegProp;
+  CONST UINT32         *RangesProp;
+  UINT64               UartBase;
+  UINT64               TpmBase;
+  EFI_STATUS           Status;
+  FVB_ADDRESS_LIST     *FvbAddressList;
+  FVB_ADDRESS_LIST_PTR *FvbAddressListPtrHobData;
 
   Base = (VOID*)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);
   ASSERT (Base != NULL);
   ASSERT (fdt_check_header (Base) == 0);
 
   FdtSize = fdt_totalsize (Base) + PcdGet32 (PcdDeviceTreeAllocationPadding);
   FdtPages = EFI_SIZE_TO_PAGES (FdtSize);
@@ -181,9 +185,25 @@ PlatformPeim (
       Status = PeiServicesInstallPpi (&mTpm2InitializationDonePpi);
     }
     ASSERT_EFI_ERROR (Status);
   }
 
   BuildFvHob (PcdGet64 (PcdFvBaseAddress), PcdGet32 (PcdFvSize));
 
+  //
+  // Allocate, initialize, and expose FVB_ADDRESS_LIST.
+  //
+  FvbAddressList = AllocateReservedPages (
+                     EFI_SIZE_TO_PAGES (sizeof *FvbAddressList));
+  ASSERT (FvbAddressList != NULL);
+  DEBUG ((DEBUG_VERBOSE, "%a: FvbAddressList @ %p\n", __FUNCTION__,
+    (VOID *)FvbAddressList));
+  FvbAddressList->Signature = FVB_ADDRESS_LIST_SIGNATURE;
+  ZeroMem (FvbAddressList->Entry, sizeof FvbAddressList->Entry);
+  FvbAddressList->Next = 0;
+  FvbAddressListPtrHobData = BuildGuidHob (&gEdkiiFvbAddressListGuid,
+                               sizeof *FvbAddressListPtrHobData);
+  ASSERT (FvbAddressListPtrHobData != NULL);
+  *FvbAddressListPtrHobData = (UINTN)FvbAddressList;
+
   return EFI_SUCCESS;
 }
-- 
2.19.1.3.g30247aa5d201


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-ArmPlatformPkg-NorFlashDxe-populate-FVB_ADDRESS_LIST.patch --]
[-- Type: text/x-patch; name="0003-ArmPlatformPkg-NorFlashDxe-populate-FVB_ADDRESS_LIST.patch", Size: 7153 bytes --]

From a656046171cd98600d4f6810f1d9f856aba19b6e Mon Sep 17 00:00:00 2001
From: Laszlo Ersek <lersek@redhat.com>
Date: Thu, 11 Mar 2021 22:16:41 +0100
Subject: [PATCH 3/4] ArmPlatformPkg/NorFlashDxe: populate FVB_ADDRESS_LIST

When the SetVirtualAddressMap() handler runs, and we convert (among other
things) the GetPhysicalAddress() FVB member function pointer, stash both
the physical and the virtual addresses of this member function, in
FVB_ADDRESS_LIST.

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf |  1 +
 ArmPlatformPkg/Drivers/NorFlashDxe/NorFlash.c      | 27 ++++++++++++++++++--
 ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c   | 11 ++++++++
 3 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf
index f8d4c2703143..1eba5f869c55 100644
--- a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf
+++ b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf
@@ -43,14 +43,15 @@ [LibraryClasses]
 
 [Guids]
   gEfiSystemNvDataFvGuid
   gEfiVariableGuid
   gEfiAuthenticatedVariableGuid
   gEfiEventVirtualAddressChangeGuid
   gEdkiiNvVarStoreFormattedGuid     ## PRODUCES ## PROTOCOL
+  gEdkiiFvbAddressListGuid
 
 [Protocols]
   gEfiBlockIoProtocolGuid
   gEfiDevicePathProtocolGuid
   gEfiFirmwareVolumeBlockProtocolGuid
   gEfiDiskIoProtocolGuid
 
diff --git a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlash.c b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlash.c
index a9e23db4461b..73faca549bda 100644
--- a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlash.c
+++ b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlash.c
@@ -3,23 +3,25 @@
   Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>
   Copyright (c) 2020, Linaro, Ltd. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
+#include <Guid/FvbAddressList.h>
 #include <Library/BaseMemoryLib.h>
 
 #include "NorFlash.h"
 
 //
 // Global variable declarations
 //
 extern NOR_FLASH_INSTANCE **mNorFlashInstances;
 extern UINT32               mNorFlashDeviceCount;
+extern FVB_ADDRESS_LIST     *mFvbAddressList;
 
 UINT32
 NorFlashReadStatusRegister (
   IN NOR_FLASH_INSTANCE     *Instance,
   IN UINTN                  SR_Address
   )
 {
@@ -939,35 +941,56 @@ NorFlashReset (
 VOID
 EFIAPI
 NorFlashVirtualNotifyEvent (
   IN EFI_EVENT        Event,
   IN VOID             *Context
   )
 {
-  UINTN Index;
+  UINT64                 OwnerSignature;
+  FVB_ADDRESS_LIST_ENTRY *Entry;
+  UINTN                  Index;
+
+  OwnerSignature = SIGNATURE_64 ('N', 'O', 'R', 'F', 'L', 'A', 'S', 'H');
+  Entry          = mFvbAddressList->Entry + mFvbAddressList->Next;
 
   for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
+    VOID *Pointer;
+
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->DeviceBaseAddress);
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->RegionBaseAddress);
 
     // Convert BlockIo protocol
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.FlushBlocks);
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.ReadBlocks);
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.Reset);
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.WriteBlocks);
 
     // Convert Fvb
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);
-    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);
+
+    Pointer = (VOID *)(UINTN)mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress;
+    Entry->OwnerSignature = OwnerSignature;
+    Entry->Address        = (UINTN)Pointer;
+    ++Entry;
+
+    EfiConvertPointer (0x0, &Pointer);
+    mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress =
+      (EFI_FVB_GET_PHYSICAL_ADDRESS)(UINTN)Pointer;
+
+    Entry->OwnerSignature = OwnerSignature;
+    Entry->Address        = (UINTN)Pointer;
+    ++Entry;
+
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Read);
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);
     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Write);
 
     if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
       EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->ShadowBuffer);
     }
   }
 
+  mFvbAddressList->Next = Entry - mFvbAddressList->Entry;
   return;
 }
diff --git a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c
index f412731200cf..fad0b8c39723 100644
--- a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c
+++ b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c
@@ -2,14 +2,15 @@
 
   Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
+#include <Guid/FvbAddressList.h>
 #include <Library/UefiLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/PcdLib.h>
 #include <Library/HobLib.h>
 #include <Library/DxeServicesTableLib.h>
@@ -21,14 +22,16 @@ STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent;
 //
 // Global variable declarations
 //
 NOR_FLASH_INSTANCE **mNorFlashInstances;
 UINT32               mNorFlashDeviceCount;
 UINTN                mFlashNvStorageVariableBase;
 EFI_EVENT            mFvbVirtualAddrChangeEvent;
+FVB_ADDRESS_LIST     *mFvbAddressList;
+
 
 NOR_FLASH_INSTANCE  mNorFlashInstanceTemplate = {
   NOR_FLASH_SIGNATURE, // Signature
   NULL, // Handle ... NEED TO BE FILLED
 
   0, // DeviceBaseAddress ... NEED TO BE FILLED
   0, // RegionBaseAddress ... NEED TO BE FILLED
@@ -318,19 +321,27 @@ NorFlashWriteFullBlock (
 EFI_STATUS
 EFIAPI
 NorFlashInitialise (
   IN EFI_HANDLE         ImageHandle,
   IN EFI_SYSTEM_TABLE   *SystemTable
   )
 {
+  VOID                    *Hob;
+  FVB_ADDRESS_LIST_PTR    *FvbAddressListPtrHobData;
   EFI_STATUS              Status;
   UINT32                  Index;
   NOR_FLASH_DESCRIPTION*  NorFlashDevices;
   BOOLEAN                 ContainVariableStorage;
 
+  Hob = GetFirstGuidHob (&gEdkiiFvbAddressListGuid);
+  ASSERT (Hob != NULL);
+  FvbAddressListPtrHobData = GET_GUID_HOB_DATA (Hob);
+  mFvbAddressList = (VOID*)(UINTN)*FvbAddressListPtrHobData;
+  ASSERT (mFvbAddressList->Signature == FVB_ADDRESS_LIST_SIGNATURE);
+
   Status = NorFlashPlatformInitialization ();
   if (EFI_ERROR(Status)) {
     DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to initialize Nor Flash devices\n"));
     return Status;
   }
 
   Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);
-- 
2.19.1.3.g30247aa5d201


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-MdeModulePkg-VariableRuntimeDxe-populate-FVB_ADDRESS_LIST.patch --]
[-- Type: text/x-patch; name="0004-MdeModulePkg-VariableRuntimeDxe-populate-FVB_ADDRESS_LIST.patch", Size: 8524 bytes --]

From f424470f69ce8811766b1118fc801238f2242596 Mon Sep 17 00:00:00 2001
From: Laszlo Ersek <lersek@redhat.com>
Date: Thu, 11 Mar 2021 22:16:41 +0100
Subject: [PATCH 4/4] MdeModulePkg/VariableRuntimeDxe: populate
 FVB_ADDRESS_LIST

When the SetVirtualAddressMap() handler runs, and we convert (among other
things) the GetPhysicalAddress() FVB member function pointer, stash both
the physical and the virtual addresses of this member function, in
FVB_ADDRESS_LIST.

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf |  2 ++
 MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h             |  2 ++
 MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c          | 36 ++++++++++++++++++--
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
index c9434df631ee..e4cc49692f2d 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
@@ -120,14 +120,16 @@ [Guids]
   gEdkiiVarErrorFlagGuid
 
   ## SOMETIMES_CONSUMES   ## Variable:L"db"
   ## SOMETIMES_CONSUMES   ## Variable:L"dbx"
   ## SOMETIMES_CONSUMES   ## Variable:L"dbt"
   gEfiImageSecurityDatabaseGuid
 
+  gEdkiiFvbAddressListGuid
+
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize      ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase      ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64    ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize                 ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize             ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize         ## CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
index 0b2bb6ae6648..77c390586d35 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
@@ -33,14 +33,15 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Library/VarCheckLib.h>
 #include <Guid/GlobalVariable.h>
 #include <Guid/EventGroup.h>
 #include <Guid/VariableFormat.h>
 #include <Guid/SystemNvDataGuid.h>
 #include <Guid/FaultTolerantWrite.h>
 #include <Guid/VarErrorFlag.h>
+#include <Guid/FvbAddressList.h>
 
 #include "PrivilegePolymorphic.h"
 
 #define NV_STORAGE_VARIABLE_BASE (EFI_PHYSICAL_ADDRESS) \
                                    (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ? \
                                     PcdGet64 (PcdFlashNvStorageVariableBase64) : \
                                     PcdGet32 (PcdFlashNvStorageVariableBase))
@@ -693,14 +694,15 @@ extern VARIABLE_MODULE_GLOBAL       *mVariableModuleGlobal;
 extern EFI_FIRMWARE_VOLUME_HEADER   *mNvFvHeaderCache;
 extern VARIABLE_STORE_HEADER        *mNvVariableCache;
 extern VARIABLE_INFO_ENTRY          *gVariableInfo;
 extern BOOLEAN                      mEndOfDxe;
 extern VAR_CHECK_REQUEST_SOURCE     mRequestSource;
 
 extern AUTH_VAR_LIB_CONTEXT_OUT     mAuthContextOut;
+extern FVB_ADDRESS_LIST             *mFvbAddressList;
 
 /**
   Finds variable in storage blocks of volatile and non-volatile storage areas.
 
   This code finds variable in storage blocks of volatile and non-volatile storage areas.
   If VariableName is an empty string, then we just return the first
   qualified variable without comparing VariableName and VendorGuid.
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
index 0fca0bb2a9b5..b7a33e3a348d 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
@@ -32,14 +32,15 @@ EDKII_VARIABLE_POLICY_PROTOCOL      mVariablePolicyProtocol    = { EDKII_VARIABL
                                                                     ProtocolIsVariablePolicyEnabled,
                                                                     RegisterVariablePolicy,
                                                                     DumpVariablePolicy,
                                                                     LockVariablePolicy };
 EDKII_VAR_CHECK_PROTOCOL            mVarCheck                  = { VarCheckRegisterSetVariableCheckHandler,
                                                                     VarCheckVariablePropertySet,
                                                                     VarCheckVariablePropertyGet };
+FVB_ADDRESS_LIST *mFvbAddressList;
 
 /**
   Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
   Record their initial State when variable write service is ready.
 
 **/
 VOID
@@ -240,26 +241,49 @@ GetFvbCountAndBuffer (
 VOID
 EFIAPI
 VariableClassAddressChangeEvent (
   IN EFI_EVENT                            Event,
   IN VOID                                 *Context
   )
 {
-  UINTN          Index;
+  UINT64                 OwnerSignature;
+  FVB_ADDRESS_LIST_ENTRY *Entry;
+  UINTN                  Index;
+
+  OwnerSignature = SIGNATURE_64 ('V', 'A', 'R', 'I', 'A', 'B', 'L', 'E');
+  Entry          = mFvbAddressList->Entry + mFvbAddressList->Next;
 
   if (mVariableModuleGlobal->FvbInstance != NULL) {
+    VOID *Pointer;
+
     EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
-    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
+
+    Pointer = (VOID *)(UINTN)mVariableModuleGlobal->FvbInstance->GetPhysicalAddress;
+    Entry->OwnerSignature = OwnerSignature;
+    Entry->Address        = (UINTN)Pointer;
+    ++Entry;
+
+    EfiConvertPointer (0x0, &Pointer);
+    mVariableModuleGlobal->FvbInstance->GetPhysicalAddress =
+      (EFI_FVB_GET_PHYSICAL_ADDRESS)(UINTN)Pointer;
+
+    Entry->OwnerSignature = OwnerSignature;
+    Entry->Address        = (UINTN)Pointer;
+    ++Entry;
+
     EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
     EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
     EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
     EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
     EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
     EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);
   }
+
+  mFvbAddressList->Next = Entry - mFvbAddressList->Entry;
+
   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);
   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes);
   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang);
   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.HobVariableBase);
   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
@@ -528,18 +552,26 @@ ProtocolIsVariablePolicyEnabled (
 EFI_STATUS
 EFIAPI
 VariableServiceInitialize (
   IN EFI_HANDLE                         ImageHandle,
   IN EFI_SYSTEM_TABLE                   *SystemTable
   )
 {
+  VOID                                  *Hob;
+  FVB_ADDRESS_LIST_PTR                  *FvbAddressListPtrHobData;
   EFI_STATUS                            Status;
   EFI_EVENT                             ReadyToBootEvent;
   EFI_EVENT                             EndOfDxeEvent;
 
+  Hob = GetFirstGuidHob (&gEdkiiFvbAddressListGuid);
+  ASSERT (Hob != NULL);
+  FvbAddressListPtrHobData = GET_GUID_HOB_DATA (Hob);
+  mFvbAddressList = (VOID*)(UINTN)*FvbAddressListPtrHobData;
+  ASSERT (mFvbAddressList->Signature == FVB_ADDRESS_LIST_SIGNATURE);
+
   Status = VariableCommonInitialize ();
   ASSERT_EFI_ERROR (Status);
 
   Status = gBS->InstallMultipleProtocolInterfaces (
                   &mHandle,
                   &gEdkiiVariableLockProtocolGuid,
                   &mVariableLock,
-- 
2.19.1.3.g30247aa5d201


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
  2021-03-11 22:25         ` Laszlo Ersek
@ 2021-03-11 22:39           ` Ard Biesheuvel
  2021-03-12  3:01             ` Jon Nettleton
                               ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2021-03-11 22:39 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: devel, jon, Hao A Wu, Liming Gao, Ard Biesheuvel (TianoCore),
	Leif Lindholm (Nuvia address)

On Thu, 11 Mar 2021 at 23:25, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Adding Ard and Leif, comments below:
>
> On 03/11/21 15:50, Laszlo Ersek wrote:
> > On 03/11/21 10:48, Jon Nettleton wrote:
>
> [...]
>
> >> And this is where the pointer gets remapped again and into the MMIO
> >> space of the nor flash.  If I remove the calls to ConvertPointer for
> >> the FvbProtocol I am still seeing those addresses getting remapped
> >> but only once and runtime works as expected.
> >>
> >> I am seeing that in
> >> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> >> &mVariableModuleGlobal->FvbInstance->* are all being converted.  It
> >> is possible this is a long standing bug and it just so happens that
> >> our configuration has caused a conflict and exposed it.
> >
> > Yes, this is curious, I noticed it too yesterday, trying to see where
> > the FVB protocol member function pointers were converted. I found that
> > OVMF's flash driver (OvmfPkg/QemuFlashFvbServicesRuntimeDxe) didn't do
> > it, but MdeModulePkg/Universal/Variable/RuntimeDxe did. That was
> > certainly strange, as the variable driver is a consumer of the
> > protocol (not the producer thereof), so I'd say it has no business
> > poking new values into the protocol interface structure.
>
> [...]
>
> > ... Strangely, the other flash (FVB) driver in edk2,
> > ArmPlatformPkg/Drivers/NorFlashDxe, *does* perform the conversion
> > itself! See NorFlashVirtualNotifyEvent().
> >
> > I don't understand that. Is it possible that, with
> > "ArmPlatformPkg/Drivers/NorFlashDxe" too, the conversion happens
> > *twice*, but (at least) one of those mappings is "identity"?
>
> Confirmed.
>
> I had to write some elaborate debug patches for determining this,
> because in ArmVirtQemu, I cannot produce DEBUG output from the
> SetVirtualAddressMap() notification functions. So here's the approach I
> took:
>
> (1) Introduce a new GUID-ed HOB structure in MdeModulePkg. The structure
> itself lives in reserved memory, but its address is exposed in a GUID-ed
> HOB. The structure is named FVB_ADDRESS_LIST, and it has the following
> fields:
>
>   - signature ("FVBADRLS" -- FVB Address List)
>   - 16 entries of:
>     - owner signature [what driver set this entry]
>     - address
>   - number of entries used (aka next entry to fill)
>
> (2) In PlatformPei, allocate and initialize this structure (in reserved
> memory), and expose its address via the GUID-ed HOB. Furthermore,
> produce a log message with the allocation address.
>
> (3) In NorFlashDxe, look up the structure via the GUID-ed HOB, in the
> entry point function; remember the address in a global variable. In the
> SetVirtualAddressMap() handler function, treat the conversion of the
> "GetPhysicalAddress" FVB member function specially: via the global
> variable pointer to FVB_ADDRESS_LIST in reserved memory, save both the
> physical (original) and the virtual (converted) address of the
> "GetPhysicalAddress" FVB member function, in new entries. As owner
> signature in both entries, use "NORFLASH".
>
> (4) In the runtime DXE variable driver, do the exact same thing, just
> use a different "owner signature" -- "VARIABLE".
>
> (5) Once the guest is up and running, run "efibootmgr --delete-timeout"
> at a root prompt in the guest, deleting the existent "Timeout" UEFI
> non-volatile variable, for verifying that the runtime variable (write)
> service is functional.
>
> (6) Using the log message from point (2):
>
> > PlatformPeim: FvbAddressList @ 13FEC9000
>
> hexdump the guest memory containing the FVB_ADDRESS_LIST, as follows:
>
> > $ virsh qemu-monitor-command aavmf.rhel7.registered --hmp xp  /268cb 0x13FEC9000
>
> Ccomments to the right of the hexdump:
>
> > 000000013fec9000: 'F' 'V' 'B' 'A' 'D' 'R' 'L' 'S'                         <- structure signature: FVBADRLS
> > 000000013fec9008: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[0], signature: NORFLASH
> > 000000013fec9010: 'T' ' ' '\xc6' ';' '\x01' '\x00' '\x00' '\x00'          <- entry[0], GetPhysicalAddress *physical*: 0x000000013bc62054
> > 000000013fec9018: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[1], signature: NORFLASH
> > 000000013fec9020: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[1], GetPhysicalAddress *virtual*: 0x00000000244e2054
> > 000000013fec9028: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[2], signature: VARIABLE
> > 000000013fec9030: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[2], GetPhysicalAddress *physical*: 0x00000000244e2054
> > 000000013fec9038: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[3], signature: VARIABLE
> > 000000013fec9040: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[3], GetPhysicalAddress *virtual*: 0x00000000244e2054
> > 000000013fec9048: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9050: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9058: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9060: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9068: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9070: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9078: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9080: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9088: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9090: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9098: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90a0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90a8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90b0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90b8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90c0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90c8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90d0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90d8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90e0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90e8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90f0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec90f8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9100: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > 000000013fec9108: '\x04' '\x00' '\x00' '\x00'                             <- number of entries used: 4
>
> This shows the following:
>
> - both NorFlashDxe and the runtime DXE variable driver converted the
>   FVB.GetPhysicalAddress member function,
>
> - the NorFlashDxe driver acted first, the runtime DXE variable driver
>   acted second,
>
> - when the runtime DXE variable driver "converted" the "physical"
>   address to virtual address, there was no change (and no crash!),
>   because the virtual address map passed in by the Linux kernel
>   apparently identity maps this area -- just as I guessed.
>
> So we definitely have a bug (only Linux's page tables save us from the
> crash); now the question is:
>
> Which driver is wrong to even attempt the conversion of the FVB member
> functions?
>
> The answer must be documented somewhere highly visible.
>
> Debug patches attached, for the record (based on commit edd46cd407ea).
>

Thanks for inviting me to this party!

So the tl;dr here is that some points get converted twice, which
usually is not a problem because the virtual address resulting from
the conversion is rarely mistaken for a physical address living in a
EFI_MEMORY_RUNTIME region.

So I agree with Laszlo's assertion that the consumer of a protocol has
no business updating its protocol pointers, so this should definitely
be fixed in the core VariableRuntime driver. However, given the
typical nature of the variable stack, i.e., a platform specfic NOR
flash driver combined with the generic FTW and variable drivers, doing
so would likely break many out of tree platforms where the NOR flash
driver does not bother to update its pointers at all.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
  2021-03-11 22:39           ` Ard Biesheuvel
@ 2021-03-12  3:01             ` Jon Nettleton
       [not found]             ` <166B792D1514133B.31346@groups.io>
  2021-03-12 19:17             ` Laszlo Ersek
  2 siblings, 0 replies; 13+ messages in thread
From: Jon Nettleton @ 2021-03-12  3:01 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Laszlo Ersek, devel, Hao A Wu, Liming Gao,
	Ard Biesheuvel (TianoCore), Leif Lindholm (Nuvia address)

On Thu, Mar 11, 2021 at 11:39 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>
> On Thu, 11 Mar 2021 at 23:25, Laszlo Ersek <lersek@redhat.com> wrote:
> >
> > Adding Ard and Leif, comments below:
> >
> > On 03/11/21 15:50, Laszlo Ersek wrote:
> > > On 03/11/21 10:48, Jon Nettleton wrote:
> >
> > [...]
> >
> > >> And this is where the pointer gets remapped again and into the MMIO
> > >> space of the nor flash.  If I remove the calls to ConvertPointer for
> > >> the FvbProtocol I am still seeing those addresses getting remapped
> > >> but only once and runtime works as expected.
> > >>
> > >> I am seeing that in
> > >> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> > >> &mVariableModuleGlobal->FvbInstance->* are all being converted.  It
> > >> is possible this is a long standing bug and it just so happens that
> > >> our configuration has caused a conflict and exposed it.
> > >
> > > Yes, this is curious, I noticed it too yesterday, trying to see where
> > > the FVB protocol member function pointers were converted. I found that
> > > OVMF's flash driver (OvmfPkg/QemuFlashFvbServicesRuntimeDxe) didn't do
> > > it, but MdeModulePkg/Universal/Variable/RuntimeDxe did. That was
> > > certainly strange, as the variable driver is a consumer of the
> > > protocol (not the producer thereof), so I'd say it has no business
> > > poking new values into the protocol interface structure.
> >
> > [...]
> >
> > > ... Strangely, the other flash (FVB) driver in edk2,
> > > ArmPlatformPkg/Drivers/NorFlashDxe, *does* perform the conversion
> > > itself! See NorFlashVirtualNotifyEvent().
> > >
> > > I don't understand that. Is it possible that, with
> > > "ArmPlatformPkg/Drivers/NorFlashDxe" too, the conversion happens
> > > *twice*, but (at least) one of those mappings is "identity"?
> >
> > Confirmed.
> >
> > I had to write some elaborate debug patches for determining this,
> > because in ArmVirtQemu, I cannot produce DEBUG output from the
> > SetVirtualAddressMap() notification functions. So here's the approach I
> > took:
> >
> > (1) Introduce a new GUID-ed HOB structure in MdeModulePkg. The structure
> > itself lives in reserved memory, but its address is exposed in a GUID-ed
> > HOB. The structure is named FVB_ADDRESS_LIST, and it has the following
> > fields:
> >
> >   - signature ("FVBADRLS" -- FVB Address List)
> >   - 16 entries of:
> >     - owner signature [what driver set this entry]
> >     - address
> >   - number of entries used (aka next entry to fill)
> >
> > (2) In PlatformPei, allocate and initialize this structure (in reserved
> > memory), and expose its address via the GUID-ed HOB. Furthermore,
> > produce a log message with the allocation address.
> >
> > (3) In NorFlashDxe, look up the structure via the GUID-ed HOB, in the
> > entry point function; remember the address in a global variable. In the
> > SetVirtualAddressMap() handler function, treat the conversion of the
> > "GetPhysicalAddress" FVB member function specially: via the global
> > variable pointer to FVB_ADDRESS_LIST in reserved memory, save both the
> > physical (original) and the virtual (converted) address of the
> > "GetPhysicalAddress" FVB member function, in new entries. As owner
> > signature in both entries, use "NORFLASH".
> >
> > (4) In the runtime DXE variable driver, do the exact same thing, just
> > use a different "owner signature" -- "VARIABLE".
> >
> > (5) Once the guest is up and running, run "efibootmgr --delete-timeout"
> > at a root prompt in the guest, deleting the existent "Timeout" UEFI
> > non-volatile variable, for verifying that the runtime variable (write)
> > service is functional.
> >
> > (6) Using the log message from point (2):
> >
> > > PlatformPeim: FvbAddressList @ 13FEC9000
> >
> > hexdump the guest memory containing the FVB_ADDRESS_LIST, as follows:
> >
> > > $ virsh qemu-monitor-command aavmf.rhel7.registered --hmp xp  /268cb 0x13FEC9000
> >
> > Ccomments to the right of the hexdump:
> >
> > > 000000013fec9000: 'F' 'V' 'B' 'A' 'D' 'R' 'L' 'S'                         <- structure signature: FVBADRLS
> > > 000000013fec9008: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[0], signature: NORFLASH
> > > 000000013fec9010: 'T' ' ' '\xc6' ';' '\x01' '\x00' '\x00' '\x00'          <- entry[0], GetPhysicalAddress *physical*: 0x000000013bc62054
> > > 000000013fec9018: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[1], signature: NORFLASH
> > > 000000013fec9020: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[1], GetPhysicalAddress *virtual*: 0x00000000244e2054
> > > 000000013fec9028: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[2], signature: VARIABLE
> > > 000000013fec9030: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[2], GetPhysicalAddress *physical*: 0x00000000244e2054
> > > 000000013fec9038: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[3], signature: VARIABLE
> > > 000000013fec9040: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[3], GetPhysicalAddress *virtual*: 0x00000000244e2054
> > > 000000013fec9048: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9050: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9058: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9060: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9068: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9070: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9078: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9080: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9088: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9090: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9098: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90a0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90a8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90b0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90b8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90c0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90c8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90d0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90d8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90e0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90e8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90f0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec90f8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9100: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > 000000013fec9108: '\x04' '\x00' '\x00' '\x00'                             <- number of entries used: 4
> >
> > This shows the following:
> >
> > - both NorFlashDxe and the runtime DXE variable driver converted the
> >   FVB.GetPhysicalAddress member function,
> >
> > - the NorFlashDxe driver acted first, the runtime DXE variable driver
> >   acted second,
> >
> > - when the runtime DXE variable driver "converted" the "physical"
> >   address to virtual address, there was no change (and no crash!),
> >   because the virtual address map passed in by the Linux kernel
> >   apparently identity maps this area -- just as I guessed.
> >
> > So we definitely have a bug (only Linux's page tables save us from the
> > crash); now the question is:
> >
> > Which driver is wrong to even attempt the conversion of the FVB member
> > functions?
> >
> > The answer must be documented somewhere highly visible.
> >
> > Debug patches attached, for the record (based on commit edd46cd407ea).
> >
>
> Thanks for inviting me to this party!
>
> So the tl;dr here is that some points get converted twice, which
> usually is not a problem because the virtual address resulting from
> the conversion is rarely mistaken for a physical address living in a
> EFI_MEMORY_RUNTIME region.
>
> So I agree with Laszlo's assertion that the consumer of a protocol has
> no business updating its protocol pointers, so this should definitely
> be fixed in the core VariableRuntime driver. However, given the
> typical nature of the variable stack, i.e., a platform specfic NOR
> flash driver combined with the generic FTW and variable drivers, doing
> so would likely break many out of tree platforms where the NOR flash
> driver does not bother to update its pointers at all.

Not ideal, but we could add a flag to Runtime Services and let the platform
specify if it is remapping the FVB.  This would allow us to not break legacy
drivers, but still easily let properly designed platforms bypass this
behaviour.  As time progressed this could be used to for a deprecation
warning, until it became the default handling of FVB pointer conversion.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
       [not found]             ` <166B792D1514133B.31346@groups.io>
@ 2021-03-12  5:59               ` Jon Nettleton
  2021-03-12 19:30                 ` Laszlo Ersek
  2021-03-12 19:52                 ` Ard Biesheuvel
  0 siblings, 2 replies; 13+ messages in thread
From: Jon Nettleton @ 2021-03-12  5:59 UTC (permalink / raw)
  To: devel, Jon Nettleton
  Cc: Ard Biesheuvel, Laszlo Ersek, Hao A Wu, Liming Gao,
	Ard Biesheuvel (TianoCore), Leif Lindholm (Nuvia address)

[-- Attachment #1: Type: text/plain, Size: 9627 bytes --]

On Fri, Mar 12, 2021 at 4:02 AM Jon Nettleton via groups.io
<jon=solid-run.com@groups.io> wrote:
>
> On Thu, Mar 11, 2021 at 11:39 PM Ard Biesheuvel <ardb@kernel.org> wrote:
> >
> > On Thu, 11 Mar 2021 at 23:25, Laszlo Ersek <lersek@redhat.com> wrote:
> > >
> > > Adding Ard and Leif, comments below:
> > >
> > > On 03/11/21 15:50, Laszlo Ersek wrote:
> > > > On 03/11/21 10:48, Jon Nettleton wrote:
> > >
> > > [...]
> > >
> > > >> And this is where the pointer gets remapped again and into the MMIO
> > > >> space of the nor flash.  If I remove the calls to ConvertPointer for
> > > >> the FvbProtocol I am still seeing those addresses getting remapped
> > > >> but only once and runtime works as expected.
> > > >>
> > > >> I am seeing that in
> > > >> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> > > >> &mVariableModuleGlobal->FvbInstance->* are all being converted.  It
> > > >> is possible this is a long standing bug and it just so happens that
> > > >> our configuration has caused a conflict and exposed it.
> > > >
> > > > Yes, this is curious, I noticed it too yesterday, trying to see where
> > > > the FVB protocol member function pointers were converted. I found that
> > > > OVMF's flash driver (OvmfPkg/QemuFlashFvbServicesRuntimeDxe) didn't do
> > > > it, but MdeModulePkg/Universal/Variable/RuntimeDxe did. That was
> > > > certainly strange, as the variable driver is a consumer of the
> > > > protocol (not the producer thereof), so I'd say it has no business
> > > > poking new values into the protocol interface structure.
> > >
> > > [...]
> > >
> > > > ... Strangely, the other flash (FVB) driver in edk2,
> > > > ArmPlatformPkg/Drivers/NorFlashDxe, *does* perform the conversion
> > > > itself! See NorFlashVirtualNotifyEvent().
> > > >
> > > > I don't understand that. Is it possible that, with
> > > > "ArmPlatformPkg/Drivers/NorFlashDxe" too, the conversion happens
> > > > *twice*, but (at least) one of those mappings is "identity"?
> > >
> > > Confirmed.
> > >
> > > I had to write some elaborate debug patches for determining this,
> > > because in ArmVirtQemu, I cannot produce DEBUG output from the
> > > SetVirtualAddressMap() notification functions. So here's the approach I
> > > took:
> > >
> > > (1) Introduce a new GUID-ed HOB structure in MdeModulePkg. The structure
> > > itself lives in reserved memory, but its address is exposed in a GUID-ed
> > > HOB. The structure is named FVB_ADDRESS_LIST, and it has the following
> > > fields:
> > >
> > >   - signature ("FVBADRLS" -- FVB Address List)
> > >   - 16 entries of:
> > >     - owner signature [what driver set this entry]
> > >     - address
> > >   - number of entries used (aka next entry to fill)
> > >
> > > (2) In PlatformPei, allocate and initialize this structure (in reserved
> > > memory), and expose its address via the GUID-ed HOB. Furthermore,
> > > produce a log message with the allocation address.
> > >
> > > (3) In NorFlashDxe, look up the structure via the GUID-ed HOB, in the
> > > entry point function; remember the address in a global variable. In the
> > > SetVirtualAddressMap() handler function, treat the conversion of the
> > > "GetPhysicalAddress" FVB member function specially: via the global
> > > variable pointer to FVB_ADDRESS_LIST in reserved memory, save both the
> > > physical (original) and the virtual (converted) address of the
> > > "GetPhysicalAddress" FVB member function, in new entries. As owner
> > > signature in both entries, use "NORFLASH".
> > >
> > > (4) In the runtime DXE variable driver, do the exact same thing, just
> > > use a different "owner signature" -- "VARIABLE".
> > >
> > > (5) Once the guest is up and running, run "efibootmgr --delete-timeout"
> > > at a root prompt in the guest, deleting the existent "Timeout" UEFI
> > > non-volatile variable, for verifying that the runtime variable (write)
> > > service is functional.
> > >
> > > (6) Using the log message from point (2):
> > >
> > > > PlatformPeim: FvbAddressList @ 13FEC9000
> > >
> > > hexdump the guest memory containing the FVB_ADDRESS_LIST, as follows:
> > >
> > > > $ virsh qemu-monitor-command aavmf.rhel7.registered --hmp xp  /268cb 0x13FEC9000
> > >
> > > Ccomments to the right of the hexdump:
> > >
> > > > 000000013fec9000: 'F' 'V' 'B' 'A' 'D' 'R' 'L' 'S'                         <- structure signature: FVBADRLS
> > > > 000000013fec9008: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[0], signature: NORFLASH
> > > > 000000013fec9010: 'T' ' ' '\xc6' ';' '\x01' '\x00' '\x00' '\x00'          <- entry[0], GetPhysicalAddress *physical*: 0x000000013bc62054
> > > > 000000013fec9018: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[1], signature: NORFLASH
> > > > 000000013fec9020: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[1], GetPhysicalAddress *virtual*: 0x00000000244e2054
> > > > 000000013fec9028: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[2], signature: VARIABLE
> > > > 000000013fec9030: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[2], GetPhysicalAddress *physical*: 0x00000000244e2054
> > > > 000000013fec9038: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[3], signature: VARIABLE
> > > > 000000013fec9040: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[3], GetPhysicalAddress *virtual*: 0x00000000244e2054
> > > > 000000013fec9048: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9050: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9058: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9060: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9068: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9070: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9078: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9080: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9088: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9090: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9098: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90a0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90a8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90b0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90b8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90c0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90c8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90d0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90d8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90e0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90e8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90f0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec90f8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9100: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
> > > > 000000013fec9108: '\x04' '\x00' '\x00' '\x00'                             <- number of entries used: 4
> > >
> > > This shows the following:
> > >
> > > - both NorFlashDxe and the runtime DXE variable driver converted the
> > >   FVB.GetPhysicalAddress member function,
> > >
> > > - the NorFlashDxe driver acted first, the runtime DXE variable driver
> > >   acted second,
> > >
> > > - when the runtime DXE variable driver "converted" the "physical"
> > >   address to virtual address, there was no change (and no crash!),
> > >   because the virtual address map passed in by the Linux kernel
> > >   apparently identity maps this area -- just as I guessed.
> > >
> > > So we definitely have a bug (only Linux's page tables save us from the
> > > crash); now the question is:
> > >
> > > Which driver is wrong to even attempt the conversion of the FVB member
> > > functions?
> > >
> > > The answer must be documented somewhere highly visible.
> > >
> > > Debug patches attached, for the record (based on commit edd46cd407ea).
> > >
> >
> > Thanks for inviting me to this party!
> >
> > So the tl;dr here is that some points get converted twice, which
> > usually is not a problem because the virtual address resulting from
> > the conversion is rarely mistaken for a physical address living in a
> > EFI_MEMORY_RUNTIME region.
> >
> > So I agree with Laszlo's assertion that the consumer of a protocol has
> > no business updating its protocol pointers, so this should definitely
> > be fixed in the core VariableRuntime driver. However, given the
> > typical nature of the variable stack, i.e., a platform specfic NOR
> > flash driver combined with the generic FTW and variable drivers, doing
> > so would likely break many out of tree platforms where the NOR flash
> > driver does not bother to update its pointers at all.
>
> Not ideal, but we could add a flag to Runtime Services and let the platform
> specify if it is remapping the FVB.  This would allow us to not break legacy
> drivers, but still easily let properly designed platforms bypass this
> behaviour.  As time progressed this could be used to for a deprecation
> warning, until it became the default handling of FVB pointer conversion.
>
Something like the attached patch possibly?

[-- Attachment #2: 0001-MdeModulePkg-Variable-VariableRuntimeDxe-Add-Bool-Pc.patch --]
[-- Type: text/x-patch, Size: 4931 bytes --]

From 126bd8bebf24e0269696f22a282a4b0340d9923b Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon@solid-run.com>
Date: Fri, 12 Mar 2021 06:52:56 +0100
Subject: [PATCH] MdeModulePkg/Variable/VariableRuntimeDxe: Add Bool
 PcdDriverConvertsFvbFuncPointers

VariableRuntimeDxe is unconditionally converting the pointers to the Fvb protocol
functions even if the platform drivers are already converting the pointers
themselves.  This leads to a double pointer conversion and can cause unexpected
runtime behaviour depending on the memory layout of the platform.

Since we don't want to break legacy and out of tree platforms we add a Bool flag
that defaults to the existing behaviour but allows platforms to only use the
pointer conversion being done in their driver implementation that produces the
FVB Protocol.

Signed-off-by: Jon Nettleton <jon@solid-run.com>
---
 MdeModulePkg/MdeModulePkg.dec                    |  6 ++++++
 .../Universal/Variable/RuntimeDxe/VariableDxe.c  | 16 +++++++++-------
 .../Variable/RuntimeDxe/VariableRuntimeDxe.inf   |  1 +
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 1483955110..07b84b1837 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -1130,6 +1130,12 @@
   # @Prompt Reclaim variable space at EndOfDxe.
   gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe|FALSE|BOOLEAN|0x30000008
 
+  ## Driver converts FVB function pointers.<BR><BR>
+  # The value is FALSE as default to retain the current behaviour and retain compatibility with out of tree platorms.<BR>
+  # If the value is set to TRUE, variable driver does not convert the FVB function pointers.<BR>
+  # @Prompt Platform driver converts FVB pointers.
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDriverConvertsFvbFuncPointers|FALSE|BOOLEAN|0x3000000b
+
   ## The size of volatile buffer. This buffer is used to store VOLATILE attribute variables.
   # @Prompt Variable storage size.
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x10000|UINT32|0x30000005
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
index 0fca0bb2a9..ede2a66682 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
@@ -247,13 +247,15 @@ VariableClassAddressChangeEvent (
   UINTN          Index;
 
   if (mVariableModuleGlobal->FvbInstance != NULL) {
-    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
-    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
-    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
-    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
-    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
-    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
-    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
+    if (!PcdGetBool (PcdDriverConvertsFvbFuncPointers)) {
+      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
+      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
+      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
+      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
+      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
+      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
+      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
+    }
     EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);
   }
   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
index c9434df631..f3373f8137 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
@@ -137,6 +137,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize           ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize  ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDriverConvertsFvbFuncPointers   ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable         ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved      ## SOMETIMES_CONSUMES
 
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
  2021-03-11 22:39           ` Ard Biesheuvel
  2021-03-12  3:01             ` Jon Nettleton
       [not found]             ` <166B792D1514133B.31346@groups.io>
@ 2021-03-12 19:17             ` Laszlo Ersek
  2 siblings, 0 replies; 13+ messages in thread
From: Laszlo Ersek @ 2021-03-12 19:17 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: devel, jon, Hao A Wu, Liming Gao, Ard Biesheuvel (TianoCore),
	Leif Lindholm (Nuvia address)

On 03/11/21 23:39, Ard Biesheuvel wrote:
> On Thu, 11 Mar 2021 at 23:25, Laszlo Ersek <lersek@redhat.com> wrote:
>>
>> Adding Ard and Leif, comments below:
>>
>> On 03/11/21 15:50, Laszlo Ersek wrote:
>>> On 03/11/21 10:48, Jon Nettleton wrote:
>>
>> [...]
>>
>>>> And this is where the pointer gets remapped again and into the MMIO
>>>> space of the nor flash.  If I remove the calls to ConvertPointer for
>>>> the FvbProtocol I am still seeing those addresses getting remapped
>>>> but only once and runtime works as expected.
>>>>
>>>> I am seeing that in
>>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
>>>> &mVariableModuleGlobal->FvbInstance->* are all being converted.  It
>>>> is possible this is a long standing bug and it just so happens that
>>>> our configuration has caused a conflict and exposed it.
>>>
>>> Yes, this is curious, I noticed it too yesterday, trying to see where
>>> the FVB protocol member function pointers were converted. I found that
>>> OVMF's flash driver (OvmfPkg/QemuFlashFvbServicesRuntimeDxe) didn't do
>>> it, but MdeModulePkg/Universal/Variable/RuntimeDxe did. That was
>>> certainly strange, as the variable driver is a consumer of the
>>> protocol (not the producer thereof), so I'd say it has no business
>>> poking new values into the protocol interface structure.
>>
>> [...]
>>
>>> ... Strangely, the other flash (FVB) driver in edk2,
>>> ArmPlatformPkg/Drivers/NorFlashDxe, *does* perform the conversion
>>> itself! See NorFlashVirtualNotifyEvent().
>>>
>>> I don't understand that. Is it possible that, with
>>> "ArmPlatformPkg/Drivers/NorFlashDxe" too, the conversion happens
>>> *twice*, but (at least) one of those mappings is "identity"?
>>
>> Confirmed.
>>
>> I had to write some elaborate debug patches for determining this,
>> because in ArmVirtQemu, I cannot produce DEBUG output from the
>> SetVirtualAddressMap() notification functions. So here's the approach I
>> took:
>>
>> (1) Introduce a new GUID-ed HOB structure in MdeModulePkg. The structure
>> itself lives in reserved memory, but its address is exposed in a GUID-ed
>> HOB. The structure is named FVB_ADDRESS_LIST, and it has the following
>> fields:
>>
>>   - signature ("FVBADRLS" -- FVB Address List)
>>   - 16 entries of:
>>     - owner signature [what driver set this entry]
>>     - address
>>   - number of entries used (aka next entry to fill)
>>
>> (2) In PlatformPei, allocate and initialize this structure (in reserved
>> memory), and expose its address via the GUID-ed HOB. Furthermore,
>> produce a log message with the allocation address.
>>
>> (3) In NorFlashDxe, look up the structure via the GUID-ed HOB, in the
>> entry point function; remember the address in a global variable. In the
>> SetVirtualAddressMap() handler function, treat the conversion of the
>> "GetPhysicalAddress" FVB member function specially: via the global
>> variable pointer to FVB_ADDRESS_LIST in reserved memory, save both the
>> physical (original) and the virtual (converted) address of the
>> "GetPhysicalAddress" FVB member function, in new entries. As owner
>> signature in both entries, use "NORFLASH".
>>
>> (4) In the runtime DXE variable driver, do the exact same thing, just
>> use a different "owner signature" -- "VARIABLE".
>>
>> (5) Once the guest is up and running, run "efibootmgr --delete-timeout"
>> at a root prompt in the guest, deleting the existent "Timeout" UEFI
>> non-volatile variable, for verifying that the runtime variable (write)
>> service is functional.
>>
>> (6) Using the log message from point (2):
>>
>>> PlatformPeim: FvbAddressList @ 13FEC9000
>>
>> hexdump the guest memory containing the FVB_ADDRESS_LIST, as follows:
>>
>>> $ virsh qemu-monitor-command aavmf.rhel7.registered --hmp xp  /268cb 0x13FEC9000
>>
>> Ccomments to the right of the hexdump:
>>
>>> 000000013fec9000: 'F' 'V' 'B' 'A' 'D' 'R' 'L' 'S'                         <- structure signature: FVBADRLS
>>> 000000013fec9008: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[0], signature: NORFLASH
>>> 000000013fec9010: 'T' ' ' '\xc6' ';' '\x01' '\x00' '\x00' '\x00'          <- entry[0], GetPhysicalAddress *physical*: 0x000000013bc62054
>>> 000000013fec9018: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[1], signature: NORFLASH
>>> 000000013fec9020: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[1], GetPhysicalAddress *virtual*: 0x00000000244e2054
>>> 000000013fec9028: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[2], signature: VARIABLE
>>> 000000013fec9030: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[2], GetPhysicalAddress *physical*: 0x00000000244e2054
>>> 000000013fec9038: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[3], signature: VARIABLE
>>> 000000013fec9040: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[3], GetPhysicalAddress *virtual*: 0x00000000244e2054
>>> 000000013fec9048: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9050: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9058: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9060: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9068: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9070: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9078: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9080: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9088: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9090: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9098: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90a0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90a8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90b0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90b8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90c0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90c8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90d0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90d8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90e0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90e8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90f0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec90f8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9100: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>> 000000013fec9108: '\x04' '\x00' '\x00' '\x00'                             <- number of entries used: 4
>>
>> This shows the following:
>>
>> - both NorFlashDxe and the runtime DXE variable driver converted the
>>   FVB.GetPhysicalAddress member function,
>>
>> - the NorFlashDxe driver acted first, the runtime DXE variable driver
>>   acted second,
>>
>> - when the runtime DXE variable driver "converted" the "physical"
>>   address to virtual address, there was no change (and no crash!),
>>   because the virtual address map passed in by the Linux kernel
>>   apparently identity maps this area -- just as I guessed.
>>
>> So we definitely have a bug (only Linux's page tables save us from the
>> crash); now the question is:
>>
>> Which driver is wrong to even attempt the conversion of the FVB member
>> functions?
>>
>> The answer must be documented somewhere highly visible.
>>
>> Debug patches attached, for the record (based on commit edd46cd407ea).
>>
> 
> Thanks for inviting me to this party!
> 
> So the tl;dr here is that some points get converted twice, which
> usually is not a problem because the virtual address resulting from
> the conversion is rarely mistaken for a physical address living in a
> EFI_MEMORY_RUNTIME region.

Ah, good point!

Where I assumed that an identity mapping must have existed, from the
OS's mappings, there's a much simpler explanation indeed:

If the "physical address" that's being converted simply doesn't fall
into a domain that's supposed to be runtime-mapped (per the "VirtualMap"
parameter of SetVirtualAddressMap()), the ConvertPointer() call simply
fails with EFI_NOT_FOUND, and the pointer is left intact.

> So I agree with Laszlo's assertion that the consumer of a protocol has
> no business updating its protocol pointers, so this should definitely
> be fixed in the core VariableRuntime driver. However, given the
> typical nature of the variable stack, i.e., a platform specfic NOR
> flash driver combined with the generic FTW and variable drivers, doing
> so would likely break many out of tree platforms where the NOR flash
> driver does not bother to update its pointers at all.

Yes, this is indeed the compatibility argument.

Where I see a gray area though is the PI spec. I checked PI v1.7
yesterday (all occurrences of "runtime"), and FVB drivers / protocols
are not required to be runtime drivers / protocol -- not even the
*possibility* is raised. The variable write arch protocol / driver must
be runtime, but how that may (or may not) translate to FVB is not
mentioned, as far as I recall.

FWIW, the variable driver bug goes back to historical commit
8a9e0b7274c69, dated 2009-03-09. The commit message is... obscure.

Hmmm... look at related commit 00f3851372eb ("retire FvbServiceLib class
in MdeModulePkg [...]", 2009-03-09). It looks like the ConvertPointer()
stuff was originally there? "Firmeware Volume BLock Service Library".

FvbServiceLib seems to have been a helper library for FVB drivers, and
so it was in its right to offer pointer conversion services...
FvbLibInitialize() was the constructor, and it registered
FvbVirtualAddressChangeNotifyEvent().

FvbServiceLib was originally added in commit 677472aae492, dated 2008-10-25.

I don't know why commit 8a9e0b7274c69 merged the pointer conversion into
the variable driver; that seems to have been wrong. But... it's been
with us for 12 years now :/

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
  2021-03-12  5:59               ` Jon Nettleton
@ 2021-03-12 19:30                 ` Laszlo Ersek
  2021-03-12 19:52                 ` Ard Biesheuvel
  1 sibling, 0 replies; 13+ messages in thread
From: Laszlo Ersek @ 2021-03-12 19:30 UTC (permalink / raw)
  To: Jon Nettleton, devel
  Cc: Ard Biesheuvel, Hao A Wu, Liming Gao, Ard Biesheuvel (TianoCore),
	Leif Lindholm (Nuvia address)

On 03/12/21 06:59, Jon Nettleton wrote:
> On Fri, Mar 12, 2021 at 4:02 AM Jon Nettleton via groups.io
> <jon=solid-run.com@groups.io> wrote:
>> On Thu, Mar 11, 2021 at 11:39 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>>> On Thu, 11 Mar 2021 at 23:25, Laszlo Ersek <lersek@redhat.com> wrote:
>>>> Adding Ard and Leif, comments below:
>>>>
>>>> On 03/11/21 15:50, Laszlo Ersek wrote:
>>>>> On 03/11/21 10:48, Jon Nettleton wrote:
>>>> [...]
>>>>
>>>>>> And this is where the pointer gets remapped again and into the MMIO
>>>>>> space of the nor flash.  If I remove the calls to ConvertPointer for
>>>>>> the FvbProtocol I am still seeing those addresses getting remapped
>>>>>> but only once and runtime works as expected.
>>>>>>
>>>>>> I am seeing that in
>>>>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
>>>>>> &mVariableModuleGlobal->FvbInstance->* are all being converted.  It
>>>>>> is possible this is a long standing bug and it just so happens that
>>>>>> our configuration has caused a conflict and exposed it.
>>>>> Yes, this is curious, I noticed it too yesterday, trying to see where
>>>>> the FVB protocol member function pointers were converted. I found that
>>>>> OVMF's flash driver (OvmfPkg/QemuFlashFvbServicesRuntimeDxe) didn't do
>>>>> it, but MdeModulePkg/Universal/Variable/RuntimeDxe did. That was
>>>>> certainly strange, as the variable driver is a consumer of the
>>>>> protocol (not the producer thereof), so I'd say it has no business
>>>>> poking new values into the protocol interface structure.
>>>> [...]
>>>>
>>>>> ... Strangely, the other flash (FVB) driver in edk2,
>>>>> ArmPlatformPkg/Drivers/NorFlashDxe, *does* perform the conversion
>>>>> itself! See NorFlashVirtualNotifyEvent().
>>>>>
>>>>> I don't understand that. Is it possible that, with
>>>>> "ArmPlatformPkg/Drivers/NorFlashDxe" too, the conversion happens
>>>>> *twice*, but (at least) one of those mappings is "identity"?
>>>> Confirmed.
>>>>
>>>> I had to write some elaborate debug patches for determining this,
>>>> because in ArmVirtQemu, I cannot produce DEBUG output from the
>>>> SetVirtualAddressMap() notification functions. So here's the approach I
>>>> took:
>>>>
>>>> (1) Introduce a new GUID-ed HOB structure in MdeModulePkg. The structure
>>>> itself lives in reserved memory, but its address is exposed in a GUID-ed
>>>> HOB. The structure is named FVB_ADDRESS_LIST, and it has the following
>>>> fields:
>>>>
>>>>   - signature ("FVBADRLS" -- FVB Address List)
>>>>   - 16 entries of:
>>>>     - owner signature [what driver set this entry]
>>>>     - address
>>>>   - number of entries used (aka next entry to fill)
>>>>
>>>> (2) In PlatformPei, allocate and initialize this structure (in reserved
>>>> memory), and expose its address via the GUID-ed HOB. Furthermore,
>>>> produce a log message with the allocation address.
>>>>
>>>> (3) In NorFlashDxe, look up the structure via the GUID-ed HOB, in the
>>>> entry point function; remember the address in a global variable. In the
>>>> SetVirtualAddressMap() handler function, treat the conversion of the
>>>> "GetPhysicalAddress" FVB member function specially: via the global
>>>> variable pointer to FVB_ADDRESS_LIST in reserved memory, save both the
>>>> physical (original) and the virtual (converted) address of the
>>>> "GetPhysicalAddress" FVB member function, in new entries. As owner
>>>> signature in both entries, use "NORFLASH".
>>>>
>>>> (4) In the runtime DXE variable driver, do the exact same thing, just
>>>> use a different "owner signature" -- "VARIABLE".
>>>>
>>>> (5) Once the guest is up and running, run "efibootmgr --delete-timeout"
>>>> at a root prompt in the guest, deleting the existent "Timeout" UEFI
>>>> non-volatile variable, for verifying that the runtime variable (write)
>>>> service is functional.
>>>>
>>>> (6) Using the log message from point (2):
>>>>
>>>>> PlatformPeim: FvbAddressList @ 13FEC9000
>>>> hexdump the guest memory containing the FVB_ADDRESS_LIST, as follows:
>>>>
>>>>> $ virsh qemu-monitor-command aavmf.rhel7.registered --hmp xp  /268cb 0x13FEC9000
>>>> Ccomments to the right of the hexdump:
>>>>
>>>>> 000000013fec9000: 'F' 'V' 'B' 'A' 'D' 'R' 'L' 'S'                         <- structure signature: FVBADRLS
>>>>> 000000013fec9008: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[0], signature: NORFLASH
>>>>> 000000013fec9010: 'T' ' ' '\xc6' ';' '\x01' '\x00' '\x00' '\x00'          <- entry[0], GetPhysicalAddress *physical*: 0x000000013bc62054
>>>>> 000000013fec9018: 'N' 'O' 'R' 'F' 'L' 'A' 'S' 'H'                         <- entry[1], signature: NORFLASH
>>>>> 000000013fec9020: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[1], GetPhysicalAddress *virtual*: 0x00000000244e2054
>>>>> 000000013fec9028: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[2], signature: VARIABLE
>>>>> 000000013fec9030: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[2], GetPhysicalAddress *physical*: 0x00000000244e2054
>>>>> 000000013fec9038: 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E'                         <- entry[3], signature: VARIABLE
>>>>> 000000013fec9040: 'T' ' ' 'N' '$' '\x00' '\x00' '\x00' '\x00'             <- entry[3], GetPhysicalAddress *virtual*: 0x00000000244e2054
>>>>> 000000013fec9048: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9050: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9058: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9060: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9068: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9070: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9078: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9080: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9088: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9090: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9098: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90a0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90a8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90b0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90b8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90c0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90c8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90d0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90d8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90e0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90e8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90f0: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec90f8: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9100: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00'
>>>>> 000000013fec9108: '\x04' '\x00' '\x00' '\x00'                             <- number of entries used: 4
>>>> This shows the following:
>>>>
>>>> - both NorFlashDxe and the runtime DXE variable driver converted the
>>>>   FVB.GetPhysicalAddress member function,
>>>>
>>>> - the NorFlashDxe driver acted first, the runtime DXE variable driver
>>>>   acted second,
>>>>
>>>> - when the runtime DXE variable driver "converted" the "physical"
>>>>   address to virtual address, there was no change (and no crash!),
>>>>   because the virtual address map passed in by the Linux kernel
>>>>   apparently identity maps this area -- just as I guessed.
>>>>
>>>> So we definitely have a bug (only Linux's page tables save us from the
>>>> crash); now the question is:
>>>>
>>>> Which driver is wrong to even attempt the conversion of the FVB member
>>>> functions?
>>>>
>>>> The answer must be documented somewhere highly visible.
>>>>
>>>> Debug patches attached, for the record (based on commit edd46cd407ea).
>>>>
>>> Thanks for inviting me to this party!
>>>
>>> So the tl;dr here is that some points get converted twice, which
>>> usually is not a problem because the virtual address resulting from
>>> the conversion is rarely mistaken for a physical address living in a
>>> EFI_MEMORY_RUNTIME region.
>>>
>>> So I agree with Laszlo's assertion that the consumer of a protocol has
>>> no business updating its protocol pointers, so this should definitely
>>> be fixed in the core VariableRuntime driver. However, given the
>>> typical nature of the variable stack, i.e., a platform specfic NOR
>>> flash driver combined with the generic FTW and variable drivers, doing
>>> so would likely break many out of tree platforms where the NOR flash
>>> driver does not bother to update its pointers at all.
>> Not ideal, but we could add a flag to Runtime Services and let the platform
>> specify if it is remapping the FVB.  This would allow us to not break legacy
>> drivers, but still easily let properly designed platforms bypass this
>> behaviour.  As time progressed this could be used to for a deprecation
>> warning, until it became the default handling of FVB pointer conversion.
>>
> Something like the attached patch possibly?
> 
> 
> 0001-MdeModulePkg-Variable-VariableRuntimeDxe-Add-Bool-Pc.patch
> 
> 
> From 126bd8bebf24e0269696f22a282a4b0340d9923b Mon Sep 17 00:00:00 2001
> From: Jon Nettleton <jon@solid-run.com>
> Date: Fri, 12 Mar 2021 06:52:56 +0100
> Subject: [PATCH] MdeModulePkg/Variable/VariableRuntimeDxe: Add Bool
>  PcdDriverConvertsFvbFuncPointers
> 
> VariableRuntimeDxe is unconditionally converting the pointers to the Fvb protocol
> functions even if the platform drivers are already converting the pointers
> themselves.  This leads to a double pointer conversion and can cause unexpected
> runtime behaviour depending on the memory layout of the platform.
> 
> Since we don't want to break legacy and out of tree platforms we add a Bool flag
> that defaults to the existing behaviour but allows platforms to only use the
> pointer conversion being done in their driver implementation that produces the
> FVB Protocol.
> 
> Signed-off-by: Jon Nettleton <jon@solid-run.com>
> ---
>  MdeModulePkg/MdeModulePkg.dec                    |  6 ++++++
>  .../Universal/Variable/RuntimeDxe/VariableDxe.c  | 16 +++++++++-------
>  .../Variable/RuntimeDxe/VariableRuntimeDxe.inf   |  1 +
>  3 files changed, 16 insertions(+), 7 deletions(-)
> 
> diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
> index 1483955110..07b84b1837 100644
> --- a/MdeModulePkg/MdeModulePkg.dec
> +++ b/MdeModulePkg/MdeModulePkg.dec
> @@ -1130,6 +1130,12 @@
>    # @Prompt Reclaim variable space at EndOfDxe.
>    gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe|FALSE|BOOLEAN|0x30000008
>  
> +  ## Driver converts FVB function pointers.<BR><BR>
> +  # The value is FALSE as default to retain the current behaviour and retain compatibility with out of tree platorms.<BR>
> +  # If the value is set to TRUE, variable driver does not convert the FVB function pointers.<BR>
> +  # @Prompt Platform driver converts FVB pointers.
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDriverConvertsFvbFuncPointers|FALSE|BOOLEAN|0x3000000b
> +
>    ## The size of volatile buffer. This buffer is used to store VOLATILE attribute variables.
>    # @Prompt Variable storage size.
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x10000|UINT32|0x30000005
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> index 0fca0bb2a9..ede2a66682 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> @@ -247,13 +247,15 @@ VariableClassAddressChangeEvent (
>    UINTN          Index;
>  
>    if (mVariableModuleGlobal->FvbInstance != NULL) {
> -    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
> -    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
> -    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
> -    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
> -    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
> -    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
> -    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
> +    if (!PcdGetBool (PcdDriverConvertsFvbFuncPointers)) {
> +      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
> +      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
> +      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
> +      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
> +      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
> +      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
> +      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
> +    }
>      EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);
>    }
>    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> index c9434df631..f3373f8137 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> @@ -137,6 +137,7 @@
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize           ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize  ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe  ## CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDriverConvertsFvbFuncPointers   ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable         ## SOMETIMES_CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved      ## SOMETIMES_CONSUMES
>  
> -- 2.27.0
> 

(1) I suggest filing a TianoCore BZ for this, and then submitting the
patch to the mailing list with git-send-email. Please don't forget to CC
the Variable Driver reviewers / maintainers.

official:

https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Development-Process

unofficial hints:

https://github.com/tianocore/tianocore.github.io/wiki/Laszlo%27s-unkempt-git-guide-for-edk2-contributors-and-maintainers

(2) I don't think removing the original condition
"mVariableModuleGlobal->FvbInstance" is valid. That condition comes from
commit 7cd69959463a ("MdeModulePkg Variable: Add emulated variable NV
mode support", 2019-01-24). The condition should likely be *restricted*
with the new condition.

(3) Rather than a PCD, I wonder if we should add a new FVB attribute bit
instead, to EFI_FVB_ATTRIBUTES_2, returned by FVB2.GetAttributes().

This would raise the topic to the PI spec's level. For an example, we
have EFI_FVB2_WEAK_ALIGNMENT (0x80000000) -- from commit 3837e91c58d4
("MdeModulePkg: Add support for weakly aligned FVs.", 2013-09-16) --,
associated with <https://mantis.uefi.org/mantis/view.php?id=839>.

Just an idea; it really needs to be commented upon by the maintainers. I
don't "insist" that it be explained in the PI spec, just saying that it
might help with the confusion.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] Conflicting virtual addresses causing Runtime Services issues
  2021-03-12  5:59               ` Jon Nettleton
  2021-03-12 19:30                 ` Laszlo Ersek
@ 2021-03-12 19:52                 ` Ard Biesheuvel
  1 sibling, 0 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2021-03-12 19:52 UTC (permalink / raw)
  To: Jon Nettleton
  Cc: devel, Laszlo Ersek, Hao A Wu, Liming Gao,
	Ard Biesheuvel (TianoCore), Leif Lindholm (Nuvia address)

On Fri, 12 Mar 2021 at 07:00, Jon Nettleton <jon@solid-run.com> wrote:
>
> On Fri, Mar 12, 2021 at 4:02 AM Jon Nettleton via groups.io
> <jon=solid-run.com@groups.io> wrote:
> >
> > On Thu, Mar 11, 2021 at 11:39 PM Ard Biesheuvel <ardb@kernel.org> wrote:
> > >
> > > On Thu, 11 Mar 2021 at 23:25, Laszlo Ersek <lersek@redhat.com> wrote:
> > > >
> > > > Adding Ard and Leif, comments below:
> > > >
...
> > > Thanks for inviting me to this party!
> > >
> > > So the tl;dr here is that some points get converted twice, which
> > > usually is not a problem because the virtual address resulting from
> > > the conversion is rarely mistaken for a physical address living in a
> > > EFI_MEMORY_RUNTIME region.
> > >
> > > So I agree with Laszlo's assertion that the consumer of a protocol has
> > > no business updating its protocol pointers, so this should definitely
> > > be fixed in the core VariableRuntime driver. However, given the
> > > typical nature of the variable stack, i.e., a platform specfic NOR
> > > flash driver combined with the generic FTW and variable drivers, doing
> > > so would likely break many out of tree platforms where the NOR flash
> > > driver does not bother to update its pointers at all.
> >
> > Not ideal, but we could add a flag to Runtime Services and let the platform
> > specify if it is remapping the FVB.  This would allow us to not break legacy
> > drivers, but still easily let properly designed platforms bypass this
> > behaviour.  As time progressed this could be used to for a deprecation
> > warning, until it became the default handling of FVB pointer conversion.
> >
> Something like the attached patch possibly?

Frankly, I don't think adding a PCD that does one or the other is the
right way to go here.

Instead, what we might do is:
- record the original values of the pointers at ExitBootServices() time
- don't touch the original values but the copies during SetVirtualAddressMap()
- in each exposed RuntimeService(), do a runtime check whether the
addresses in the protocol struct are equal to the converted copies,
and if not, update them.

This functionality should be enabled by default, but can be opted out
of by a platform if we dedicate a PCD to it that defaults to enabled.
At some point, we could add some kind of deprecation warning if the
PCD is enabled, and have a path forward to actually retiring it
completely.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-03-12 19:52 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-03-10  8:04 Conflicting virtual addresses causing Runtime Services issues Jon Nettleton
2021-03-10 14:52 ` [edk2-devel] " Laszlo Ersek
2021-03-11  6:53   ` Jon Nettleton
     [not found]   ` <166B374585A9D8FC.18699@groups.io>
2021-03-11  9:48     ` Jon Nettleton
2021-03-11 14:50       ` Laszlo Ersek
2021-03-11 15:49         ` Jon Nettleton
2021-03-11 22:25         ` Laszlo Ersek
2021-03-11 22:39           ` Ard Biesheuvel
2021-03-12  3:01             ` Jon Nettleton
     [not found]             ` <166B792D1514133B.31346@groups.io>
2021-03-12  5:59               ` Jon Nettleton
2021-03-12 19:30                 ` Laszlo Ersek
2021-03-12 19:52                 ` Ard Biesheuvel
2021-03-12 19:17             ` Laszlo Ersek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox