public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* Re: ArmVirt and Self-Updating Code
       [not found] ` <DB9PR08MB67464B261E4F1815BCDD7C289D199@DB9PR08MB6746.eurprd08.prod.outlook.com>
@ 2021-07-22 14:54   ` Bret Barkelew
  2021-07-22 15:14     ` Ard Biesheuvel
  0 siblings, 1 reply; 12+ messages in thread
From: Bret Barkelew @ 2021-07-22 14:54 UTC (permalink / raw)
  To: Thomas Abraham, Ard Biesheuvel (TianoCore), Lindholm, Leif,
	Laszlo Ersek, Marvin Häuser, Sami Mujawar,
	devel@edk2.groups.io
  Cc: nd

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

Expanding audience to the full dev list…
See below…

- Bret

From: Thomas Abraham<mailto:thomas.abraham@arm.com>
Sent: Wednesday, July 7, 2021 11:07 PM
To: Bret Barkelew<mailto:Bret.Barkelew@microsoft.com>; Ard Biesheuvel (TianoCore)<mailto:ardb+tianocore@kernel.org>; Lindholm, Leif<mailto:leif@nuviainc.com>; Laszlo Ersek<mailto:lersek@redhat.com>; Marvin Häuser<mailto:mhaeuser@posteo.de>; Sami Mujawar<mailto:sami.mujawar@arm.com>
Cc: nd<mailto:nd@arm.com>
Subject: [EXTERNAL] RE: ArmVirt and Self-Updating Code

+ Sami

From: Bret Barkelew <Bret.Barkelew@microsoft.com>
Sent: Thursday, July 8, 2021 11:05 AM
To: Thomas Abraham <thomas.abraham@arm.com>; Ard Biesheuvel (TianoCore) <ardb+tianocore@kernel.org>; Lindholm, Leif <leif@nuviainc.com>; Laszlo Ersek <lersek@redhat.com>; Marvin Häuser <mhaeuser@posteo.de>
Subject: ArmVirt and Self-Updating Code

All,

Marvin asked me a question on the UEFI Talkbox Discord that’s a little beyond my ken…

“There is self-relocating code in ArmVirtPkg:
https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/ArmVirtPkg/PrePi/PrePi.c#L133-L165<https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Ftianocore%2Fedk2%2Fblob%2F17143c4837393d42c484b42d1789b85b2cff1aaf%2FArmVirtPkg%2FPrePi%2FPrePi.c%23L133-L165&data=04%7C01%7CBret.Barkelew%40microsoft.com%7C7f8b266a81d44c853f6108d941d6a804%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637613212486760659%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=Qe54pIgdrQiP%2Bb9WNOhSRqbWWsJ8FG4ukaYvjRYGfig%3D&reserved=0>
According to comments in the ASM, it seems like this is for Linux-based RAM boot (I saw further stuff for KVM, so it makes sense I guess?). It seems unfortunate it cannot be mapped into a known address range so that self-relocation is not necessary, but that's out of my scope to understand.

“Now, StandaloneMmPkg has similar (self-)relocation code too: https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386<https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Ftianocore%2Fedk2%2Fblob%2F17143c4837393d42c484b42d1789b85b2cff1aaf%2FStandaloneMmPkg%2FLibrary%2FStandaloneMmCoreEntryPoint%2FAArch64%2FStandaloneMmCoreEntryPoint.c%23L379-L386&data=04%7C01%7CBret.Barkelew%40microsoft.com%7C7f8b266a81d44c853f6108d941d6a804%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637613212486770613%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=HwixIAI%2FnnBRL4lWtdbooRRwps9gOj%2FEekr55DtXE44%3D&reserved=0>
Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above. The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158<https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Ftianocore%2Fedk2%2Fblob%2F17143c4837393d42c484b42d1789b85b2cff1aaf%2FStandaloneMmPkg%2FLibrary%2FStandaloneMmCoreEntryPoint%2FAArch64%2FSetPermissions.c%23L131-L158&data=04%7C01%7CBret.Barkelew%40microsoft.com%7C7f8b266a81d44c853f6108d941d6a804%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637613212486770613%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=YcA%2B9yB8lHvCCSMOK8jbfxLXuO1KReB2zjNn9Jcqmc0%3D&reserved=0>

“This yields the following questions to me:
1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”

Hoping that one of you could get me closer to an answer for him. Also happy to take this to the greater mailing list, but thought I’d avoid churn.

Thanks in advance!
- Bret



[-- Attachment #2: Type: text/html, Size: 7803 bytes --]

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

* Re: ArmVirt and Self-Updating Code
  2021-07-22 14:54   ` ArmVirt and Self-Updating Code Bret Barkelew
@ 2021-07-22 15:14     ` Ard Biesheuvel
  2021-07-23  9:54       ` Marvin Häuser
  0 siblings, 1 reply; 12+ messages in thread
From: Ard Biesheuvel @ 2021-07-22 15:14 UTC (permalink / raw)
  To: Bret Barkelew
  Cc: Thomas Abraham, Ard Biesheuvel (TianoCore), Lindholm, Leif,
	Laszlo Ersek, Marvin Häuser, Sami Mujawar,
	devel@edk2.groups.io, nd

On Thu, 22 Jul 2021 at 16:54, Bret Barkelew <Bret.Barkelew@microsoft.com> wrote:
>
> Expanding audience to the full dev list…
>
> See below…
>
>
>
> - Bret
>
>
>
> From: Thomas Abraham
> Sent: Wednesday, July 7, 2021 11:07 PM
> To: Bret Barkelew; Ard Biesheuvel (TianoCore); Lindholm, Leif; Laszlo Ersek; Marvin Häuser; Sami Mujawar
> Cc: nd
> Subject: [EXTERNAL] RE: ArmVirt and Self-Updating Code
>
>
>
> + Sami
>
>
>
> From: Bret Barkelew <Bret.Barkelew@microsoft.com>
> Sent: Thursday, July 8, 2021 11:05 AM
> To: Thomas Abraham <thomas.abraham@arm.com>; Ard Biesheuvel (TianoCore) <ardb+tianocore@kernel.org>; Lindholm, Leif <leif@nuviainc.com>; Laszlo Ersek <lersek@redhat.com>; Marvin Häuser <mhaeuser@posteo.de>
> Subject: ArmVirt and Self-Updating Code
>
>
>
> All,
>
>
>
> Marvin asked me a question on the UEFI Talkbox Discord that’s a little beyond my ken…
>
>
>
> “There is self-relocating code in ArmVirtPkg:
>
> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/ArmVirtPkg/PrePi/PrePi.c#L133-L165
>
> According to comments in the ASM, it seems like this is for Linux-based RAM boot (I saw further stuff for KVM, so it makes sense I guess?). It seems unfortunate it cannot be mapped into a known address range so that self-relocation is not necessary, but that's out of my scope to understand.
>

"Mapping" implies that the MMU is on, but this code boots with the MMU
off. Unlike x86, ARM does not define any physical address ranges that
are guaranteed to be backed by DRAM, so a portable image either needs
to be fully position independent, or carry the metadata it needs to
relocate itself as it is invoked.

>
>
> “Now, StandaloneMmPkg has similar (self-)relocation code too: https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386
>
> Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above.

No.

> The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
>
> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158
>
>
>
> “This yields the following questions to me:
>
> 1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
>

It is not spawned by the normal world code that runs UEFI. It is a
secure world component that runs in a completely different execution
context (TrustZone). The code does run with the MMU enabled from the
start, but running from an a priori fixed offset was considered to be
a security hazard, so we added self relocation support.

The alternative would have been to add metadata to the StMmCore
component that can be interpreted by the secure world component that
loads it, but this would go beyond any existing specs, and make
portability more problematic.

> 2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
>

No and no. Standalone MM has nothing to do with the code that runs as
part of UEFI itself. ArmPlatformPkg is completely separate from
StandaloneMmPkg.

> 3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
>

SecCore contains a PE/COFF loader, so all subsequent modules are
loaded normally. This is similar to the ArmVirtQemuKernel
self-relocating SEC module, which only relocates itself in this
manner, and relies on standard PE/COFF metadata for loading other
modules.


> 4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”
>

trustedfirmware.org may have some useful documentation.

>
>
> Hoping that one of you could get me closer to an answer for him. Also happy to take this to the greater mailing list, but thought I’d avoid churn.
>
>
>
> Thanks in advance!
>
> - Bret
>
>
>
>

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

* Re: ArmVirt and Self-Updating Code
  2021-07-22 15:14     ` Ard Biesheuvel
@ 2021-07-23  9:54       ` Marvin Häuser
  2021-07-23 10:13         ` Ard Biesheuvel
  0 siblings, 1 reply; 12+ messages in thread
From: Marvin Häuser @ 2021-07-23  9:54 UTC (permalink / raw)
  To: Ard Biesheuvel, Bret Barkelew
  Cc: Thomas Abraham, Ard Biesheuvel (TianoCore), Lindholm, Leif,
	Laszlo Ersek, Sami Mujawar, devel@edk2.groups.io, nd

On 22.07.21 17:14, Ard Biesheuvel wrote:
> On Thu, 22 Jul 2021 at 16:54, Bret Barkelew<Bret.Barkelew@microsoft.com>  wrote:
>> Expanding audience to the full dev list…
>>
>> See below…
>>
>>
>>
>> - Bret
>>
>>
>>
>> From: Thomas Abraham
>> Sent: Wednesday, July 7, 2021 11:07 PM
>> To: Bret Barkelew; Ard Biesheuvel (TianoCore); Lindholm, Leif; Laszlo Ersek; Marvin Häuser; Sami Mujawar
>> Cc: nd
>> Subject: [EXTERNAL] RE: ArmVirt and Self-Updating Code
>>
>>
>>
>> + Sami
>>
>>
>>
>> From: Bret Barkelew<Bret.Barkelew@microsoft.com>
>> Sent: Thursday, July 8, 2021 11:05 AM
>> To: Thomas Abraham<thomas.abraham@arm.com>; Ard Biesheuvel (TianoCore)<ardb+tianocore@kernel.org>; Lindholm, Leif<leif@nuviainc.com>; Laszlo Ersek<lersek@redhat.com>; Marvin Häuser<mhaeuser@posteo.de>
>> Subject: ArmVirt and Self-Updating Code
>>
>>
>>
>> All,
>>
>>
>>
>> Marvin asked me a question on the UEFI Talkbox Discord that’s a little beyond my ken…
>>
>>
>>
>> “There is self-relocating code in ArmVirtPkg:
>>
>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/ArmVirtPkg/PrePi/PrePi.c#L133-L165
>>
>> According to comments in the ASM, it seems like this is for Linux-based RAM boot (I saw further stuff for KVM, so it makes sense I guess?). It seems unfortunate it cannot be mapped into a known address range so that self-relocation is not necessary, but that's out of my scope to understand.
>>
> "Mapping" implies that the MMU is on, but this code boots with the MMU
> off. Unlike x86, ARM does not define any physical address ranges that
> are guaranteed to be backed by DRAM, so a portable image either needs
> to be fully position independent, or carry the metadata it needs to
> relocate itself as it is invoked.

And I understood it right that the idea is to use "-fpie" to
1) have all control flow instructions be position-independent (i.e. 
jumps, calls, etc; ARM docs don't spill it out, but vaguely imply this 
always is possible?), and
2) emit a GOT, which ends up being converted to PE/COFF Relocations (-> 
self-relocation), for global data that cannot be referenced relatively? 
Is there any way to know/force that no symbol in GOT is accessed up 
until the end of the self-relocation process?

>> “Now, StandaloneMmPkg has similar (self-)relocation code too:https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386
>>
>> Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above.
> No.
>
>> The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
>>
>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158

As per your comments below, I think SecCore should not be located here. 
Is the Standalone MM core of *type* SecCore in the FFS (without *being* 
SecCore)? This confused me the most.

>> “This yields the following questions to me:
>>
>> 1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
>>
> It is not spawned by the normal world code that runs UEFI. It is a
> secure world component that runs in a completely different execution
> context (TrustZone). The code does run with the MMU enabled from the
> start, but running from an a priori fixed offset was considered to be
> a security hazard, so we added self relocation support.
>
> The alternative would have been to add metadata to the StMmCore
> component that can be interpreted by the secure world component that
> loads it, but this would go beyond any existing specs, and make
> portability more problematic.
>
>> 2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
>>
> No and no. Standalone MM has nothing to do with the code that runs as
> part of UEFI itself. ArmPlatformPkg is completely separate from
> StandaloneMmPkg.
>
>> 3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
>>
> SecCore contains a PE/COFF loader, so all subsequent modules are
> loaded normally. This is similar to the ArmVirtQemuKernel
> self-relocating SEC module, which only relocates itself in this
> manner, and relies on standard PE/COFF metadata for loading other
> modules.

Interesting... this definitely is vastly different from the x86 side of 
things. I think most things became very clear. Thanks a lot!

>> 4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”
>>
> trustedfirmware.org may have some useful documentation.

I'll check it some time, hopefully this weekend. Thanks!

Best regards,
Marvin

>> Hoping that one of you could get me closer to an answer for him. Also happy to take this to the greater mailing list, but thought I’d avoid churn.
>>
>>
>>
>> Thanks in advance!
>>
>> - Bret
>>
>>
>>
>>


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

* Re: ArmVirt and Self-Updating Code
  2021-07-23  9:54       ` Marvin Häuser
@ 2021-07-23 10:13         ` Ard Biesheuvel
  2021-07-23 10:47           ` Marvin Häuser
  0 siblings, 1 reply; 12+ messages in thread
From: Ard Biesheuvel @ 2021-07-23 10:13 UTC (permalink / raw)
  To: Marvin Häuser
  Cc: Bret Barkelew, Thomas Abraham, Ard Biesheuvel (TianoCore),
	Lindholm, Leif, Laszlo Ersek, Sami Mujawar, devel@edk2.groups.io,
	nd

On Fri, 23 Jul 2021 at 11:55, Marvin Häuser <mhaeuser@posteo.de> wrote:
>
> On 22.07.21 17:14, Ard Biesheuvel wrote:
> > On Thu, 22 Jul 2021 at 16:54, Bret Barkelew<Bret.Barkelew@microsoft.com>  wrote:
> >> Expanding audience to the full dev list…
> >>
> >> See below…
> >>
> >>
> >>
> >> - Bret
> >>
> >>
> >>
> >> From: Thomas Abraham
> >> Sent: Wednesday, July 7, 2021 11:07 PM
> >> To: Bret Barkelew; Ard Biesheuvel (TianoCore); Lindholm, Leif; Laszlo Ersek; Marvin Häuser; Sami Mujawar
> >> Cc: nd
> >> Subject: [EXTERNAL] RE: ArmVirt and Self-Updating Code
> >>
> >>
> >>
> >> + Sami
> >>
> >>
> >>
> >> From: Bret Barkelew<Bret.Barkelew@microsoft.com>
> >> Sent: Thursday, July 8, 2021 11:05 AM
> >> To: Thomas Abraham<thomas.abraham@arm.com>; Ard Biesheuvel (TianoCore)<ardb+tianocore@kernel.org>; Lindholm, Leif<leif@nuviainc.com>; Laszlo Ersek<lersek@redhat.com>; Marvin Häuser<mhaeuser@posteo.de>
> >> Subject: ArmVirt and Self-Updating Code
> >>
> >>
> >>
> >> All,
> >>
> >>
> >>
> >> Marvin asked me a question on the UEFI Talkbox Discord that’s a little beyond my ken…
> >>
> >>
> >>
> >> “There is self-relocating code in ArmVirtPkg:
> >>
> >> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/ArmVirtPkg/PrePi/PrePi.c#L133-L165
> >>
> >> According to comments in the ASM, it seems like this is for Linux-based RAM boot (I saw further stuff for KVM, so it makes sense I guess?). It seems unfortunate it cannot be mapped into a known address range so that self-relocation is not necessary, but that's out of my scope to understand.
> >>
> > "Mapping" implies that the MMU is on, but this code boots with the MMU
> > off. Unlike x86, ARM does not define any physical address ranges that
> > are guaranteed to be backed by DRAM, so a portable image either needs
> > to be fully position independent, or carry the metadata it needs to
> > relocate itself as it is invoked.
>
> And I understood it right that the idea is to use "-fpie" to
> 1) have all control flow instructions be position-independent (i.e.
> jumps, calls, etc; ARM docs don't spill it out, but vaguely imply this
> always is possible?), and

The primary reason to use -fpie and PIE linking is to ensure that the
resulting ELF executable contains a RELA section that describes every
location in the binary where a memory address is stored that needs to
be updated according to the actual placement in memory. The side
effect of -fpie is that position independent global references are
emitted (i.e., ADRP/ADD instructions which are relative to the program
counter). However, the AArch64 compiler uses those by default anyway,
so for this it is not strictly needed.

> 2) emit a GOT, which ends up being converted to PE/COFF Relocations (->
> self-relocation), for global data that cannot be referenced relatively?
> Is there any way to know/force that no symbol in GOT is accessed up
> until the end of the self-relocation process?
>

It is not really a GOT. Actually, a GOT is undesirable, as it forces
global variables to be referenced via an absolute address, even when a
relative reference could be used.

For instance, a statically initialized pointer always carries an
absolute address, and so it always needs an entry in the RELA table

E.g.,

int foo = 10; // external linkage
static int *bar = &foo;

In this case, there is no way to use relative addressing because the
address of foo is taken at build time.

However, if bar would be something like

static int *bar() { return &foo; }

the address is only taken at runtime, and the compiler can use a
relative reference instead, and no RELA entry is needed. With a GOT,
we force the compiler to allocate a variable that holds the absolute
address, which we would prefer to avoid.

> >> “Now, StandaloneMmPkg has similar (self-)relocation code too:https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386
> >>
> >> Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above.
> > No.
> >
> >> The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
> >>
> >> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158
>
> As per your comments below, I think SecCore should not be located here.
> Is the Standalone MM core of *type* SecCore in the FFS (without *being*
> SecCore)? This confused me the most.
>

If the FFS SecCore section type is used here, it does not mean that
the image is a SEC image in the strict PI sense.

Perhaps we were just too lazy to add a new type to the FFS spec?

> >> “This yields the following questions to me:
> >>
> >> 1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
> >>
> > It is not spawned by the normal world code that runs UEFI. It is a
> > secure world component that runs in a completely different execution
> > context (TrustZone). The code does run with the MMU enabled from the
> > start, but running from an a priori fixed offset was considered to be
> > a security hazard, so we added self relocation support.
> >
> > The alternative would have been to add metadata to the StMmCore
> > component that can be interpreted by the secure world component that
> > loads it, but this would go beyond any existing specs, and make
> > portability more problematic.
> >
> >> 2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
> >>
> > No and no. Standalone MM has nothing to do with the code that runs as
> > part of UEFI itself. ArmPlatformPkg is completely separate from
> > StandaloneMmPkg.
> >
> >> 3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
> >>
> > SecCore contains a PE/COFF loader, so all subsequent modules are
> > loaded normally. This is similar to the ArmVirtQemuKernel
> > self-relocating SEC module, which only relocates itself in this
> > manner, and relies on standard PE/COFF metadata for loading other
> > modules.
>
> Interesting... this definitely is vastly different from the x86 side of
> things. I think most things became very clear. Thanks a lot!
>
> >> 4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”
> >>
> > trustedfirmware.org may have some useful documentation.
>
> I'll check it some time, hopefully this weekend. Thanks!
>

My pleasure.

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

* Re: ArmVirt and Self-Updating Code
  2021-07-23 10:13         ` Ard Biesheuvel
@ 2021-07-23 10:47           ` Marvin Häuser
  2021-07-23 14:09             ` Ard Biesheuvel
  0 siblings, 1 reply; 12+ messages in thread
From: Marvin Häuser @ 2021-07-23 10:47 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Bret Barkelew, Thomas Abraham, Ard Biesheuvel (TianoCore),
	Lindholm, Leif, Laszlo Ersek, Sami Mujawar, devel@edk2.groups.io,
	nd

On 23.07.21 12:13, Ard Biesheuvel wrote:
> On Fri, 23 Jul 2021 at 11:55, Marvin Häuser <mhaeuser@posteo.de> wrote:
>> On 22.07.21 17:14, Ard Biesheuvel wrote:
>>> On Thu, 22 Jul 2021 at 16:54, Bret Barkelew<Bret.Barkelew@microsoft.com>  wrote:
>>>> Expanding audience to the full dev list…
>>>>
>>>> See below…
>>>>
>>>>
>>>>
>>>> - Bret
>>>>
>>>>
>>>>
>>>> From: Thomas Abraham
>>>> Sent: Wednesday, July 7, 2021 11:07 PM
>>>> To: Bret Barkelew; Ard Biesheuvel (TianoCore); Lindholm, Leif; Laszlo Ersek; Marvin Häuser; Sami Mujawar
>>>> Cc: nd
>>>> Subject: [EXTERNAL] RE: ArmVirt and Self-Updating Code
>>>>
>>>>
>>>>
>>>> + Sami
>>>>
>>>>
>>>>
>>>> From: Bret Barkelew<Bret.Barkelew@microsoft.com>
>>>> Sent: Thursday, July 8, 2021 11:05 AM
>>>> To: Thomas Abraham<thomas.abraham@arm.com>; Ard Biesheuvel (TianoCore)<ardb+tianocore@kernel.org>; Lindholm, Leif<leif@nuviainc.com>; Laszlo Ersek<lersek@redhat.com>; Marvin Häuser<mhaeuser@posteo.de>
>>>> Subject: ArmVirt and Self-Updating Code
>>>>
>>>>
>>>>
>>>> All,
>>>>
>>>>
>>>>
>>>> Marvin asked me a question on the UEFI Talkbox Discord that’s a little beyond my ken…
>>>>
>>>>
>>>>
>>>> “There is self-relocating code in ArmVirtPkg:
>>>>
>>>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/ArmVirtPkg/PrePi/PrePi.c#L133-L165
>>>>
>>>> According to comments in the ASM, it seems like this is for Linux-based RAM boot (I saw further stuff for KVM, so it makes sense I guess?). It seems unfortunate it cannot be mapped into a known address range so that self-relocation is not necessary, but that's out of my scope to understand.
>>>>
>>> "Mapping" implies that the MMU is on, but this code boots with the MMU
>>> off. Unlike x86, ARM does not define any physical address ranges that
>>> are guaranteed to be backed by DRAM, so a portable image either needs
>>> to be fully position independent, or carry the metadata it needs to
>>> relocate itself as it is invoked.
>> And I understood it right that the idea is to use "-fpie" to
>> 1) have all control flow instructions be position-independent (i.e.
>> jumps, calls, etc; ARM docs don't spill it out, but vaguely imply this
>> always is possible?), and
> The primary reason to use -fpie and PIE linking is to ensure that the
> resulting ELF executable contains a RELA section that describes every
> location in the binary where a memory address is stored that needs to
> be updated according to the actual placement in memory. The side
> effect of -fpie is that position independent global references are
> emitted (i.e., ADRP/ADD instructions which are relative to the program
> counter). However, the AArch64 compiler uses those by default anyway,
> so for this it is not strictly needed.
>
>> 2) emit a GOT, which ends up being converted to PE/COFF Relocations (->
>> self-relocation), for global data that cannot be referenced relatively?
>> Is there any way to know/force that no symbol in GOT is accessed up
>> until the end of the self-relocation process?
>>
> It is not really a GOT. Actually, a GOT is undesirable, as it forces
> global variables to be referenced via an absolute address, even when a
> relative reference could be used.

Hmm, the GCC docs say a GOT is used for "all constant addresses" (I took 
it as "absolute"?), it is kind of vague. I understood it this way:
1) no-pie emits relocations that can target the .text and .data sections 
for instructions that embed and variables that hold an absolute address 
(I thought this was RELA?)
2) pie emits a GOT such that there are no relocations as described in 
1), because all absolute addresses are indirected by GOT (just GOT 
references are relocated)

If I understood the process right, but the term (GOT) is wrong, sorry, 
that is what I gathered from the docs. :)
I have a x86 + PE background, so ARM + ELF is a bit of a learning curve...

> For instance, a statically initialized pointer always carries an
> absolute address, and so it always needs an entry in the RELA table
>
> E.g.,
>
> int foo = 10; // external linkage
> static int *bar = &foo;
>
> In this case, there is no way to use relative addressing because the
> address of foo is taken at build time.
>
> However, if bar would be something like
>
> static int *bar() { return &foo; }
>
> the address is only taken at runtime, and the compiler can use a
> relative reference instead, and no RELA entry is needed. With a GOT,
> we force the compiler to allocate a variable that holds the absolute
> address, which we would prefer to avoid.

And this is not forced by whatever table -fpie uses, as per my 
understanding above?

>>>> “Now, StandaloneMmPkg has similar (self-)relocation code too:https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386
>>>>
>>>> Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above.
>>> No.
>>>
>>>> The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
>>>>
>>>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158
>> As per your comments below, I think SecCore should not be located here.
>> Is the Standalone MM core of *type* SecCore in the FFS (without *being*
>> SecCore)? This confused me the most.
>>
> If the FFS SecCore section type is used here, it does not mean that
> the image is a SEC image in the strict PI sense.
>
> Perhaps we were just too lazy to add a new type to the FFS spec?

That is what I meant to imply with the middle question (well, not 
necessarily "lazy", for ARM there simply seems to not be any reason to 
distinguish if the environments are fully separate), just wanted to make 
sure I understand what the code does before modifying it.

Thank you again!

Best regards,
Marvin

>>>> “This yields the following questions to me:
>>>>
>>>> 1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
>>>>
>>> It is not spawned by the normal world code that runs UEFI. It is a
>>> secure world component that runs in a completely different execution
>>> context (TrustZone). The code does run with the MMU enabled from the
>>> start, but running from an a priori fixed offset was considered to be
>>> a security hazard, so we added self relocation support.
>>>
>>> The alternative would have been to add metadata to the StMmCore
>>> component that can be interpreted by the secure world component that
>>> loads it, but this would go beyond any existing specs, and make
>>> portability more problematic.
>>>
>>>> 2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
>>>>
>>> No and no. Standalone MM has nothing to do with the code that runs as
>>> part of UEFI itself. ArmPlatformPkg is completely separate from
>>> StandaloneMmPkg.
>>>
>>>> 3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
>>>>
>>> SecCore contains a PE/COFF loader, so all subsequent modules are
>>> loaded normally. This is similar to the ArmVirtQemuKernel
>>> self-relocating SEC module, which only relocates itself in this
>>> manner, and relies on standard PE/COFF metadata for loading other
>>> modules.
>> Interesting... this definitely is vastly different from the x86 side of
>> things. I think most things became very clear. Thanks a lot!
>>
>>>> 4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”
>>>>
>>> trustedfirmware.org may have some useful documentation.
>> I'll check it some time, hopefully this weekend. Thanks!
>>
> My pleasure.


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

* Re: ArmVirt and Self-Updating Code
  2021-07-23 10:47           ` Marvin Häuser
@ 2021-07-23 14:09             ` Ard Biesheuvel
  2021-07-23 14:27               ` Marvin Häuser
  0 siblings, 1 reply; 12+ messages in thread
From: Ard Biesheuvel @ 2021-07-23 14:09 UTC (permalink / raw)
  To: Marvin Häuser
  Cc: Bret Barkelew, Thomas Abraham, Ard Biesheuvel (TianoCore),
	Lindholm, Leif, Laszlo Ersek, Sami Mujawar, devel@edk2.groups.io,
	nd

On Fri, 23 Jul 2021 at 12:47, Marvin Häuser <mhaeuser@posteo.de> wrote:
>
> On 23.07.21 12:13, Ard Biesheuvel wrote:
> > On Fri, 23 Jul 2021 at 11:55, Marvin Häuser <mhaeuser@posteo.de> wrote:
> >> On 22.07.21 17:14, Ard Biesheuvel wrote:
> >>> On Thu, 22 Jul 2021 at 16:54, Bret Barkelew<Bret.Barkelew@microsoft.com>  wrote:
> >>>> Expanding audience to the full dev list…
> >>>>
> >>>> See below…
> >>>>
> >>>>
> >>>>
> >>>> - Bret
> >>>>
> >>>>
> >>>>
> >>>> From: Thomas Abraham
> >>>> Sent: Wednesday, July 7, 2021 11:07 PM
> >>>> To: Bret Barkelew; Ard Biesheuvel (TianoCore); Lindholm, Leif; Laszlo Ersek; Marvin Häuser; Sami Mujawar
> >>>> Cc: nd
> >>>> Subject: [EXTERNAL] RE: ArmVirt and Self-Updating Code
> >>>>
> >>>>
> >>>>
> >>>> + Sami
> >>>>
> >>>>
> >>>>
> >>>> From: Bret Barkelew<Bret.Barkelew@microsoft.com>
> >>>> Sent: Thursday, July 8, 2021 11:05 AM
> >>>> To: Thomas Abraham<thomas.abraham@arm.com>; Ard Biesheuvel (TianoCore)<ardb+tianocore@kernel.org>; Lindholm, Leif<leif@nuviainc.com>; Laszlo Ersek<lersek@redhat.com>; Marvin Häuser<mhaeuser@posteo.de>
> >>>> Subject: ArmVirt and Self-Updating Code
> >>>>
> >>>>
> >>>>
> >>>> All,
> >>>>
> >>>>
> >>>>
> >>>> Marvin asked me a question on the UEFI Talkbox Discord that’s a little beyond my ken…
> >>>>
> >>>>
> >>>>
> >>>> “There is self-relocating code in ArmVirtPkg:
> >>>>
> >>>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/ArmVirtPkg/PrePi/PrePi.c#L133-L165
> >>>>
> >>>> According to comments in the ASM, it seems like this is for Linux-based RAM boot (I saw further stuff for KVM, so it makes sense I guess?). It seems unfortunate it cannot be mapped into a known address range so that self-relocation is not necessary, but that's out of my scope to understand.
> >>>>
> >>> "Mapping" implies that the MMU is on, but this code boots with the MMU
> >>> off. Unlike x86, ARM does not define any physical address ranges that
> >>> are guaranteed to be backed by DRAM, so a portable image either needs
> >>> to be fully position independent, or carry the metadata it needs to
> >>> relocate itself as it is invoked.
> >> And I understood it right that the idea is to use "-fpie" to
> >> 1) have all control flow instructions be position-independent (i.e.
> >> jumps, calls, etc; ARM docs don't spill it out, but vaguely imply this
> >> always is possible?), and
> > The primary reason to use -fpie and PIE linking is to ensure that the
> > resulting ELF executable contains a RELA section that describes every
> > location in the binary where a memory address is stored that needs to
> > be updated according to the actual placement in memory. The side
> > effect of -fpie is that position independent global references are
> > emitted (i.e., ADRP/ADD instructions which are relative to the program
> > counter). However, the AArch64 compiler uses those by default anyway,
> > so for this it is not strictly needed.
> >
> >> 2) emit a GOT, which ends up being converted to PE/COFF Relocations (->
> >> self-relocation), for global data that cannot be referenced relatively?
> >> Is there any way to know/force that no symbol in GOT is accessed up
> >> until the end of the self-relocation process?
> >>
> > It is not really a GOT. Actually, a GOT is undesirable, as it forces
> > global variables to be referenced via an absolute address, even when a
> > relative reference could be used.
>
> Hmm, the GCC docs say a GOT is used for "all constant addresses" (I took
> it as "absolute"?), it is kind of vague. I understood it this way:
> 1) no-pie emits relocations that can target the .text and .data sections
> for instructions that embed and variables that hold an absolute address
> (I thought this was RELA?)
> 2) pie emits a GOT such that there are no relocations as described in
> 1), because all absolute addresses are indirected by GOT (just GOT
> references are relocated)
>

Correct. And this works really well for shared libraries, where all
text and data sections can be shared between processes, as they will
not be modified by the loader. All locations targeted by relocations
will be nicely lumped together in the GOT.

However, for bare metal style programs, there is no sharing, and there
is no advantage to lumping anything together. It is much better to use
relative references where possible, and simply apply relocations
wherever needed across the text and data sections,

> If I understood the process right, but the term (GOT) is wrong, sorry,
> that is what I gathered from the docs. :)
> I have a x86 + PE background, so ARM + ELF is a bit of a learning curve...
>

The GOT is a special data structure used for implicit variable
accesses, i.e., global vars used in the code. Statically initialized
pointer variables are the other category, which are not code, and for
which the same considerations do not apply, given that the right value
simply needs to be stored in the variable before the program starts.

> > For instance, a statically initialized pointer always carries an
> > absolute address, and so it always needs an entry in the RELA table
> >
> > E.g.,
> >
> > int foo = 10; // external linkage
> > static int *bar = &foo;
> >
> > In this case, there is no way to use relative addressing because the
> > address of foo is taken at build time.
> >
> > However, if bar would be something like
> >
> > static int *bar() { return &foo; }
> >
> > the address is only taken at runtime, and the compiler can use a
> > relative reference instead, and no RELA entry is needed. With a GOT,
> > we force the compiler to allocate a variable that holds the absolute
> > address, which we would prefer to avoid.
>
> And this is not forced by whatever table -fpie uses, as per my
> understanding above?
>

The selection of 'code model' as it is called is controlled by GCC's
-mcmodel= argument, which defaults to 'small' on AArch64, regardless
of whether you use PIC/PIE or not.

> >>>> “Now, StandaloneMmPkg has similar (self-)relocation code too:https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386
> >>>>
> >>>> Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above.
> >>> No.
> >>>
> >>>> The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
> >>>>
> >>>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158
> >> As per your comments below, I think SecCore should not be located here.
> >> Is the Standalone MM core of *type* SecCore in the FFS (without *being*
> >> SecCore)? This confused me the most.
> >>
> > If the FFS SecCore section type is used here, it does not mean that
> > the image is a SEC image in the strict PI sense.
> >
> > Perhaps we were just too lazy to add a new type to the FFS spec?
>
> That is what I meant to imply with the middle question (well, not
> necessarily "lazy", for ARM there simply seems to not be any reason to
> distinguish if the environments are fully separate), just wanted to make
> sure I understand what the code does before modifying it.
>
> Thank you again!
>
> Best regards,
> Marvin
>
> >>>> “This yields the following questions to me:
> >>>>
> >>>> 1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
> >>>>
> >>> It is not spawned by the normal world code that runs UEFI. It is a
> >>> secure world component that runs in a completely different execution
> >>> context (TrustZone). The code does run with the MMU enabled from the
> >>> start, but running from an a priori fixed offset was considered to be
> >>> a security hazard, so we added self relocation support.
> >>>
> >>> The alternative would have been to add metadata to the StMmCore
> >>> component that can be interpreted by the secure world component that
> >>> loads it, but this would go beyond any existing specs, and make
> >>> portability more problematic.
> >>>
> >>>> 2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
> >>>>
> >>> No and no. Standalone MM has nothing to do with the code that runs as
> >>> part of UEFI itself. ArmPlatformPkg is completely separate from
> >>> StandaloneMmPkg.
> >>>
> >>>> 3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
> >>>>
> >>> SecCore contains a PE/COFF loader, so all subsequent modules are
> >>> loaded normally. This is similar to the ArmVirtQemuKernel
> >>> self-relocating SEC module, which only relocates itself in this
> >>> manner, and relies on standard PE/COFF metadata for loading other
> >>> modules.
> >> Interesting... this definitely is vastly different from the x86 side of
> >> things. I think most things became very clear. Thanks a lot!
> >>
> >>>> 4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”
> >>>>
> >>> trustedfirmware.org may have some useful documentation.
> >> I'll check it some time, hopefully this weekend. Thanks!
> >>
> > My pleasure.
>

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

* Re: ArmVirt and Self-Updating Code
  2021-07-23 14:09             ` Ard Biesheuvel
@ 2021-07-23 14:27               ` Marvin Häuser
  2021-07-23 14:34                 ` Ard Biesheuvel
  0 siblings, 1 reply; 12+ messages in thread
From: Marvin Häuser @ 2021-07-23 14:27 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Bret Barkelew, Thomas Abraham, Ard Biesheuvel (TianoCore),
	Lindholm, Leif, Laszlo Ersek, Sami Mujawar, devel@edk2.groups.io,
	nd



On 23.07.21 16:09, Ard Biesheuvel wrote:
> On Fri, 23 Jul 2021 at 12:47, Marvin Häuser <mhaeuser@posteo.de> wrote:
>> On 23.07.21 12:13, Ard Biesheuvel wrote:
>>> On Fri, 23 Jul 2021 at 11:55, Marvin Häuser <mhaeuser@posteo.de> wrote:
>>>> On 22.07.21 17:14, Ard Biesheuvel wrote:
>>>>> On Thu, 22 Jul 2021 at 16:54, Bret Barkelew<Bret.Barkelew@microsoft.com>  wrote:
>>>>>> Expanding audience to the full dev list…
>>>>>>
>>>>>> See below…
>>>>>>
>>>>>>
>>>>>>
>>>>>> - Bret
>>>>>>
>>>>>>
>>>>>>
>>>>>> From: Thomas Abraham
>>>>>> Sent: Wednesday, July 7, 2021 11:07 PM
>>>>>> To: Bret Barkelew; Ard Biesheuvel (TianoCore); Lindholm, Leif; Laszlo Ersek; Marvin Häuser; Sami Mujawar
>>>>>> Cc: nd
>>>>>> Subject: [EXTERNAL] RE: ArmVirt and Self-Updating Code
>>>>>>
>>>>>>
>>>>>>
>>>>>> + Sami
>>>>>>
>>>>>>
>>>>>>
>>>>>> From: Bret Barkelew<Bret.Barkelew@microsoft.com>
>>>>>> Sent: Thursday, July 8, 2021 11:05 AM
>>>>>> To: Thomas Abraham<thomas.abraham@arm.com>; Ard Biesheuvel (TianoCore)<ardb+tianocore@kernel.org>; Lindholm, Leif<leif@nuviainc.com>; Laszlo Ersek<lersek@redhat.com>; Marvin Häuser<mhaeuser@posteo.de>
>>>>>> Subject: ArmVirt and Self-Updating Code
>>>>>>
>>>>>>
>>>>>>
>>>>>> All,
>>>>>>
>>>>>>
>>>>>>
>>>>>> Marvin asked me a question on the UEFI Talkbox Discord that’s a little beyond my ken…
>>>>>>
>>>>>>
>>>>>>
>>>>>> “There is self-relocating code in ArmVirtPkg:
>>>>>>
>>>>>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/ArmVirtPkg/PrePi/PrePi.c#L133-L165
>>>>>>
>>>>>> According to comments in the ASM, it seems like this is for Linux-based RAM boot (I saw further stuff for KVM, so it makes sense I guess?). It seems unfortunate it cannot be mapped into a known address range so that self-relocation is not necessary, but that's out of my scope to understand.
>>>>>>
>>>>> "Mapping" implies that the MMU is on, but this code boots with the MMU
>>>>> off. Unlike x86, ARM does not define any physical address ranges that
>>>>> are guaranteed to be backed by DRAM, so a portable image either needs
>>>>> to be fully position independent, or carry the metadata it needs to
>>>>> relocate itself as it is invoked.
>>>> And I understood it right that the idea is to use "-fpie" to
>>>> 1) have all control flow instructions be position-independent (i.e.
>>>> jumps, calls, etc; ARM docs don't spill it out, but vaguely imply this
>>>> always is possible?), and
>>> The primary reason to use -fpie and PIE linking is to ensure that the
>>> resulting ELF executable contains a RELA section that describes every
>>> location in the binary where a memory address is stored that needs to
>>> be updated according to the actual placement in memory. The side
>>> effect of -fpie is that position independent global references are
>>> emitted (i.e., ADRP/ADD instructions which are relative to the program
>>> counter). However, the AArch64 compiler uses those by default anyway,
>>> so for this it is not strictly needed.
>>>
>>>> 2) emit a GOT, which ends up being converted to PE/COFF Relocations (->
>>>> self-relocation), for global data that cannot be referenced relatively?
>>>> Is there any way to know/force that no symbol in GOT is accessed up
>>>> until the end of the self-relocation process?

Do you maybe have one final comment regarding that second question, 
please? :)
Let's drop "GOT" and make it "any instruction that requires prior 
relocation to function correctly".

>>> It is not really a GOT. Actually, a GOT is undesirable, as it forces
>>> global variables to be referenced via an absolute address, even when a
>>> relative reference could be used.
>> Hmm, the GCC docs say a GOT is used for "all constant addresses" (I took
>> it as "absolute"?), it is kind of vague. I understood it this way:
>> 1) no-pie emits relocations that can target the .text and .data sections
>> for instructions that embed and variables that hold an absolute address
>> (I thought this was RELA?)
>> 2) pie emits a GOT such that there are no relocations as described in
>> 1), because all absolute addresses are indirected by GOT (just GOT
>> references are relocated)
>>
> Correct. And this works really well for shared libraries, where all
> text and data sections can be shared between processes, as they will
> not be modified by the loader. All locations targeted by relocations
> will be nicely lumped together in the GOT.
>
> However, for bare metal style programs, there is no sharing, and there
> is no advantage to lumping anything together. It is much better to use
> relative references where possible, and simply apply relocations
> wherever needed across the text and data sections,
>
>> If I understood the process right, but the term (GOT) is wrong, sorry,
>> that is what I gathered from the docs. :)
>> I have a x86 + PE background, so ARM + ELF is a bit of a learning curve...
>>
> The GOT is a special data structure used for implicit variable
> accesses, i.e., global vars used in the code. Statically initialized
> pointer variables are the other category, which are not code, and for
> which the same considerations do not apply, given that the right value
> simply needs to be stored in the variable before the program starts.
>
>>> For instance, a statically initialized pointer always carries an
>>> absolute address, and so it always needs an entry in the RELA table
>>>
>>> E.g.,
>>>
>>> int foo = 10; // external linkage
>>> static int *bar = &foo;
>>>
>>> In this case, there is no way to use relative addressing because the
>>> address of foo is taken at build time.
>>>
>>> However, if bar would be something like
>>>
>>> static int *bar() { return &foo; }
>>>
>>> the address is only taken at runtime, and the compiler can use a
>>> relative reference instead, and no RELA entry is needed. With a GOT,
>>> we force the compiler to allocate a variable that holds the absolute
>>> address, which we would prefer to avoid.
>> And this is not forced by whatever table -fpie uses, as per my
>> understanding above?
>>
> The selection of 'code model' as it is called is controlled by GCC's
> -mcmodel= argument, which defaults to 'small' on AArch64, regardless
> of whether you use PIC/PIE or not.

Aha, makes sense, thanks!

Best regards,
Marvin

>>>>>> “Now, StandaloneMmPkg has similar (self-)relocation code too:https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386
>>>>>>
>>>>>> Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above.
>>>>> No.
>>>>>
>>>>>> The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
>>>>>>
>>>>>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158
>>>> As per your comments below, I think SecCore should not be located here.
>>>> Is the Standalone MM core of *type* SecCore in the FFS (without *being*
>>>> SecCore)? This confused me the most.
>>>>
>>> If the FFS SecCore section type is used here, it does not mean that
>>> the image is a SEC image in the strict PI sense.
>>>
>>> Perhaps we were just too lazy to add a new type to the FFS spec?
>> That is what I meant to imply with the middle question (well, not
>> necessarily "lazy", for ARM there simply seems to not be any reason to
>> distinguish if the environments are fully separate), just wanted to make
>> sure I understand what the code does before modifying it.
>>
>> Thank you again!
>>
>> Best regards,
>> Marvin
>>
>>>>>> “This yields the following questions to me:
>>>>>>
>>>>>> 1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
>>>>>>
>>>>> It is not spawned by the normal world code that runs UEFI. It is a
>>>>> secure world component that runs in a completely different execution
>>>>> context (TrustZone). The code does run with the MMU enabled from the
>>>>> start, but running from an a priori fixed offset was considered to be
>>>>> a security hazard, so we added self relocation support.
>>>>>
>>>>> The alternative would have been to add metadata to the StMmCore
>>>>> component that can be interpreted by the secure world component that
>>>>> loads it, but this would go beyond any existing specs, and make
>>>>> portability more problematic.
>>>>>
>>>>>> 2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
>>>>>>
>>>>> No and no. Standalone MM has nothing to do with the code that runs as
>>>>> part of UEFI itself. ArmPlatformPkg is completely separate from
>>>>> StandaloneMmPkg.
>>>>>
>>>>>> 3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
>>>>>>
>>>>> SecCore contains a PE/COFF loader, so all subsequent modules are
>>>>> loaded normally. This is similar to the ArmVirtQemuKernel
>>>>> self-relocating SEC module, which only relocates itself in this
>>>>> manner, and relies on standard PE/COFF metadata for loading other
>>>>> modules.
>>>> Interesting... this definitely is vastly different from the x86 side of
>>>> things. I think most things became very clear. Thanks a lot!
>>>>
>>>>>> 4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”
>>>>>>
>>>>> trustedfirmware.org may have some useful documentation.
>>>> I'll check it some time, hopefully this weekend. Thanks!
>>>>
>>> My pleasure.


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

* Re: ArmVirt and Self-Updating Code
  2021-07-23 14:27               ` Marvin Häuser
@ 2021-07-23 14:34                 ` Ard Biesheuvel
  2021-07-31 19:08                   ` Marvin Häuser
  0 siblings, 1 reply; 12+ messages in thread
From: Ard Biesheuvel @ 2021-07-23 14:34 UTC (permalink / raw)
  To: Marvin Häuser
  Cc: Bret Barkelew, Thomas Abraham, Ard Biesheuvel (TianoCore),
	Lindholm, Leif, Laszlo Ersek, Sami Mujawar, devel@edk2.groups.io,
	nd

On Fri, 23 Jul 2021 at 16:27, Marvin Häuser <mhaeuser@posteo.de> wrote:
>
>
>
> On 23.07.21 16:09, Ard Biesheuvel wrote:
> > On Fri, 23 Jul 2021 at 12:47, Marvin Häuser <mhaeuser@posteo.de> wrote:
> >> On 23.07.21 12:13, Ard Biesheuvel wrote:
> >>> On Fri, 23 Jul 2021 at 11:55, Marvin Häuser <mhaeuser@posteo.de> wrote:
...
> >>>> 2) emit a GOT, which ends up being converted to PE/COFF Relocations (->
> >>>> self-relocation), for global data that cannot be referenced relatively?
> >>>> Is there any way to know/force that no symbol in GOT is accessed up
> >>>> until the end of the self-relocation process?
>
> Do you maybe have one final comment regarding that second question,
> please? :)

The RELA section is not converted into PE/COFF relocations. This would
not achieve a lot, given that no prior PE/COFF loader exists to
process them. There is a snippet of asm code in the startup code that
processes the R_AARCH64_RELATIVE relocation entries before calling
into C code.

This also gives us the guarantee that no GOT indirections are
dereferenced, given that our asm code simply does not do that.

> Let's drop "GOT" and make it "any instruction that requires prior
> relocation to function correctly".
>

The thing to keep in mind here is that R_AARCH64_RELATIVE relocations
never target instructions, but only memory locations that carry
absolute addresses. This could be locations in .rodata or .data
(global vars carrying pointer values), or GOT entries.

> >>> It is not really a GOT. Actually, a GOT is undesirable, as it forces
> >>> global variables to be referenced via an absolute address, even when a
> >>> relative reference could be used.
> >> Hmm, the GCC docs say a GOT is used for "all constant addresses" (I took
> >> it as "absolute"?), it is kind of vague. I understood it this way:
> >> 1) no-pie emits relocations that can target the .text and .data sections
> >> for instructions that embed and variables that hold an absolute address
> >> (I thought this was RELA?)
> >> 2) pie emits a GOT such that there are no relocations as described in
> >> 1), because all absolute addresses are indirected by GOT (just GOT
> >> references are relocated)
> >>
> > Correct. And this works really well for shared libraries, where all
> > text and data sections can be shared between processes, as they will
> > not be modified by the loader. All locations targeted by relocations
> > will be nicely lumped together in the GOT.
> >
> > However, for bare metal style programs, there is no sharing, and there
> > is no advantage to lumping anything together. It is much better to use
> > relative references where possible, and simply apply relocations
> > wherever needed across the text and data sections,
> >
> >> If I understood the process right, but the term (GOT) is wrong, sorry,
> >> that is what I gathered from the docs. :)
> >> I have a x86 + PE background, so ARM + ELF is a bit of a learning curve...
> >>
> > The GOT is a special data structure used for implicit variable
> > accesses, i.e., global vars used in the code. Statically initialized
> > pointer variables are the other category, which are not code, and for
> > which the same considerations do not apply, given that the right value
> > simply needs to be stored in the variable before the program starts.
> >
> >>> For instance, a statically initialized pointer always carries an
> >>> absolute address, and so it always needs an entry in the RELA table
> >>>
> >>> E.g.,
> >>>
> >>> int foo = 10; // external linkage
> >>> static int *bar = &foo;
> >>>
> >>> In this case, there is no way to use relative addressing because the
> >>> address of foo is taken at build time.
> >>>
> >>> However, if bar would be something like
> >>>
> >>> static int *bar() { return &foo; }
> >>>
> >>> the address is only taken at runtime, and the compiler can use a
> >>> relative reference instead, and no RELA entry is needed. With a GOT,
> >>> we force the compiler to allocate a variable that holds the absolute
> >>> address, which we would prefer to avoid.
> >> And this is not forced by whatever table -fpie uses, as per my
> >> understanding above?
> >>
> > The selection of 'code model' as it is called is controlled by GCC's
> > -mcmodel= argument, which defaults to 'small' on AArch64, regardless
> > of whether you use PIC/PIE or not.
>
> Aha, makes sense, thanks!
>
> Best regards,
> Marvin
>
> >>>>>> “Now, StandaloneMmPkg has similar (self-)relocation code too:https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386
> >>>>>>
> >>>>>> Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above.
> >>>>> No.
> >>>>>
> >>>>>> The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
> >>>>>>
> >>>>>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158
> >>>> As per your comments below, I think SecCore should not be located here.
> >>>> Is the Standalone MM core of *type* SecCore in the FFS (without *being*
> >>>> SecCore)? This confused me the most.
> >>>>
> >>> If the FFS SecCore section type is used here, it does not mean that
> >>> the image is a SEC image in the strict PI sense.
> >>>
> >>> Perhaps we were just too lazy to add a new type to the FFS spec?
> >> That is what I meant to imply with the middle question (well, not
> >> necessarily "lazy", for ARM there simply seems to not be any reason to
> >> distinguish if the environments are fully separate), just wanted to make
> >> sure I understand what the code does before modifying it.
> >>
> >> Thank you again!
> >>
> >> Best regards,
> >> Marvin
> >>
> >>>>>> “This yields the following questions to me:
> >>>>>>
> >>>>>> 1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
> >>>>>>
> >>>>> It is not spawned by the normal world code that runs UEFI. It is a
> >>>>> secure world component that runs in a completely different execution
> >>>>> context (TrustZone). The code does run with the MMU enabled from the
> >>>>> start, but running from an a priori fixed offset was considered to be
> >>>>> a security hazard, so we added self relocation support.
> >>>>>
> >>>>> The alternative would have been to add metadata to the StMmCore
> >>>>> component that can be interpreted by the secure world component that
> >>>>> loads it, but this would go beyond any existing specs, and make
> >>>>> portability more problematic.
> >>>>>
> >>>>>> 2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
> >>>>>>
> >>>>> No and no. Standalone MM has nothing to do with the code that runs as
> >>>>> part of UEFI itself. ArmPlatformPkg is completely separate from
> >>>>> StandaloneMmPkg.
> >>>>>
> >>>>>> 3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
> >>>>>>
> >>>>> SecCore contains a PE/COFF loader, so all subsequent modules are
> >>>>> loaded normally. This is similar to the ArmVirtQemuKernel
> >>>>> self-relocating SEC module, which only relocates itself in this
> >>>>> manner, and relies on standard PE/COFF metadata for loading other
> >>>>> modules.
> >>>> Interesting... this definitely is vastly different from the x86 side of
> >>>> things. I think most things became very clear. Thanks a lot!
> >>>>
> >>>>>> 4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”
> >>>>>>
> >>>>> trustedfirmware.org may have some useful documentation.
> >>>> I'll check it some time, hopefully this weekend. Thanks!
> >>>>
> >>> My pleasure.
>

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

* Re: ArmVirt and Self-Updating Code
  2021-07-23 14:34                 ` Ard Biesheuvel
@ 2021-07-31 19:08                   ` Marvin Häuser
  2021-08-01 16:33                     ` Ard Biesheuvel
  0 siblings, 1 reply; 12+ messages in thread
From: Marvin Häuser @ 2021-07-31 19:08 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Bret Barkelew, Thomas Abraham, Ard Biesheuvel (TianoCore),
	Lindholm, Leif, Laszlo Ersek, Sami Mujawar, devel@edk2.groups.io,
	nd

On 23.07.21 16:34, Ard Biesheuvel wrote:
> On Fri, 23 Jul 2021 at 16:27, Marvin Häuser <mhaeuser@posteo.de> wrote:
>>
>>
>> On 23.07.21 16:09, Ard Biesheuvel wrote:
>>> On Fri, 23 Jul 2021 at 12:47, Marvin Häuser <mhaeuser@posteo.de> wrote:
>>>> On 23.07.21 12:13, Ard Biesheuvel wrote:
>>>>> On Fri, 23 Jul 2021 at 11:55, Marvin Häuser <mhaeuser@posteo.de> wrote:
> ...
>>>>>> 2) emit a GOT, which ends up being converted to PE/COFF Relocations (->
>>>>>> self-relocation), for global data that cannot be referenced relatively?
>>>>>> Is there any way to know/force that no symbol in GOT is accessed up
>>>>>> until the end of the self-relocation process?
>> Do you maybe have one final comment regarding that second question,
>> please? :)
> The RELA section is not converted into PE/COFF relocations. This would
> not achieve a lot, given that no prior PE/COFF loader exists to
> process them. There is a snippet of asm code in the startup code that
> processes the R_AARCH64_RELATIVE relocation entries before calling
> into C code.

I searched for said ASM code till my fingers fell asleep and at last 
found this: 
https://github.com/tianocore/edk2/commit/b16fd231f6d8124fa05a0f086840934b8709faf9#diff-3d563cc4775c7720900f4895bf619eed06291044aaa277fcc57eddc7618351a1L12-R148

If I understand the commit message correctly, it is basically "pray the 
C code does not use globals at all", which is fair enough, so maybe I 
should document this in my proposed new library? I trust that this is 
enough of a constraint for both ARM and AArch64, because I do not know 
them at all.

What worries me is that StandaloneMmCore has no such ASM entry point at 
all and instead it's just executing C directly. Also, it is not passed 
the "-fno-jump-tables" flag that is commented to be important in the 
commit linked above.

Best regards,
Marvin

> This also gives us the guarantee that no GOT indirections are
> dereferenced, given that our asm code simply does not do that.
>
>> Let's drop "GOT" and make it "any instruction that requires prior
>> relocation to function correctly".
>>
> The thing to keep in mind here is that R_AARCH64_RELATIVE relocations
> never target instructions, but only memory locations that carry
> absolute addresses. This could be locations in .rodata or .data
> (global vars carrying pointer values), or GOT entries.
>
>>>>> It is not really a GOT. Actually, a GOT is undesirable, as it forces
>>>>> global variables to be referenced via an absolute address, even when a
>>>>> relative reference could be used.
>>>> Hmm, the GCC docs say a GOT is used for "all constant addresses" (I took
>>>> it as "absolute"?), it is kind of vague. I understood it this way:
>>>> 1) no-pie emits relocations that can target the .text and .data sections
>>>> for instructions that embed and variables that hold an absolute address
>>>> (I thought this was RELA?)
>>>> 2) pie emits a GOT such that there are no relocations as described in
>>>> 1), because all absolute addresses are indirected by GOT (just GOT
>>>> references are relocated)
>>>>
>>> Correct. And this works really well for shared libraries, where all
>>> text and data sections can be shared between processes, as they will
>>> not be modified by the loader. All locations targeted by relocations
>>> will be nicely lumped together in the GOT.
>>>
>>> However, for bare metal style programs, there is no sharing, and there
>>> is no advantage to lumping anything together. It is much better to use
>>> relative references where possible, and simply apply relocations
>>> wherever needed across the text and data sections,
>>>
>>>> If I understood the process right, but the term (GOT) is wrong, sorry,
>>>> that is what I gathered from the docs. :)
>>>> I have a x86 + PE background, so ARM + ELF is a bit of a learning curve...
>>>>
>>> The GOT is a special data structure used for implicit variable
>>> accesses, i.e., global vars used in the code. Statically initialized
>>> pointer variables are the other category, which are not code, and for
>>> which the same considerations do not apply, given that the right value
>>> simply needs to be stored in the variable before the program starts.
>>>
>>>>> For instance, a statically initialized pointer always carries an
>>>>> absolute address, and so it always needs an entry in the RELA table
>>>>>
>>>>> E.g.,
>>>>>
>>>>> int foo = 10; // external linkage
>>>>> static int *bar = &foo;
>>>>>
>>>>> In this case, there is no way to use relative addressing because the
>>>>> address of foo is taken at build time.
>>>>>
>>>>> However, if bar would be something like
>>>>>
>>>>> static int *bar() { return &foo; }
>>>>>
>>>>> the address is only taken at runtime, and the compiler can use a
>>>>> relative reference instead, and no RELA entry is needed. With a GOT,
>>>>> we force the compiler to allocate a variable that holds the absolute
>>>>> address, which we would prefer to avoid.
>>>> And this is not forced by whatever table -fpie uses, as per my
>>>> understanding above?
>>>>
>>> The selection of 'code model' as it is called is controlled by GCC's
>>> -mcmodel= argument, which defaults to 'small' on AArch64, regardless
>>> of whether you use PIC/PIE or not.
>> Aha, makes sense, thanks!
>>
>> Best regards,
>> Marvin
>>
>>>>>>>> “Now, StandaloneMmPkg has similar (self-)relocation code too:https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386
>>>>>>>>
>>>>>>>> Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above.
>>>>>>> No.
>>>>>>>
>>>>>>>> The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
>>>>>>>>
>>>>>>>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158
>>>>>> As per your comments below, I think SecCore should not be located here.
>>>>>> Is the Standalone MM core of *type* SecCore in the FFS (without *being*
>>>>>> SecCore)? This confused me the most.
>>>>>>
>>>>> If the FFS SecCore section type is used here, it does not mean that
>>>>> the image is a SEC image in the strict PI sense.
>>>>>
>>>>> Perhaps we were just too lazy to add a new type to the FFS spec?
>>>> That is what I meant to imply with the middle question (well, not
>>>> necessarily "lazy", for ARM there simply seems to not be any reason to
>>>> distinguish if the environments are fully separate), just wanted to make
>>>> sure I understand what the code does before modifying it.
>>>>
>>>> Thank you again!
>>>>
>>>> Best regards,
>>>> Marvin
>>>>
>>>>>>>> “This yields the following questions to me:
>>>>>>>>
>>>>>>>> 1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
>>>>>>>>
>>>>>>> It is not spawned by the normal world code that runs UEFI. It is a
>>>>>>> secure world component that runs in a completely different execution
>>>>>>> context (TrustZone). The code does run with the MMU enabled from the
>>>>>>> start, but running from an a priori fixed offset was considered to be
>>>>>>> a security hazard, so we added self relocation support.
>>>>>>>
>>>>>>> The alternative would have been to add metadata to the StMmCore
>>>>>>> component that can be interpreted by the secure world component that
>>>>>>> loads it, but this would go beyond any existing specs, and make
>>>>>>> portability more problematic.
>>>>>>>
>>>>>>>> 2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
>>>>>>>>
>>>>>>> No and no. Standalone MM has nothing to do with the code that runs as
>>>>>>> part of UEFI itself. ArmPlatformPkg is completely separate from
>>>>>>> StandaloneMmPkg.
>>>>>>>
>>>>>>>> 3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
>>>>>>>>
>>>>>>> SecCore contains a PE/COFF loader, so all subsequent modules are
>>>>>>> loaded normally. This is similar to the ArmVirtQemuKernel
>>>>>>> self-relocating SEC module, which only relocates itself in this
>>>>>>> manner, and relies on standard PE/COFF metadata for loading other
>>>>>>> modules.
>>>>>> Interesting... this definitely is vastly different from the x86 side of
>>>>>> things. I think most things became very clear. Thanks a lot!
>>>>>>
>>>>>>>> 4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”
>>>>>>>>
>>>>>>> trustedfirmware.org may have some useful documentation.
>>>>>> I'll check it some time, hopefully this weekend. Thanks!
>>>>>>
>>>>> My pleasure.


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

* Re: ArmVirt and Self-Updating Code
  2021-07-31 19:08                   ` Marvin Häuser
@ 2021-08-01 16:33                     ` Ard Biesheuvel
  2021-08-01 21:40                       ` [edk2-devel] " Marvin Häuser
  0 siblings, 1 reply; 12+ messages in thread
From: Ard Biesheuvel @ 2021-08-01 16:33 UTC (permalink / raw)
  To: Marvin Häuser
  Cc: Bret Barkelew, Thomas Abraham, Ard Biesheuvel (TianoCore),
	Lindholm, Leif, Laszlo Ersek, Sami Mujawar, devel@edk2.groups.io,
	nd

On Sat, 31 Jul 2021 at 21:08, Marvin Häuser <mhaeuser@posteo.de> wrote:
>
> On 23.07.21 16:34, Ard Biesheuvel wrote:
> > On Fri, 23 Jul 2021 at 16:27, Marvin Häuser <mhaeuser@posteo.de> wrote:
> >>
> >>
> >> On 23.07.21 16:09, Ard Biesheuvel wrote:
> >>> On Fri, 23 Jul 2021 at 12:47, Marvin Häuser <mhaeuser@posteo.de> wrote:
> >>>> On 23.07.21 12:13, Ard Biesheuvel wrote:
> >>>>> On Fri, 23 Jul 2021 at 11:55, Marvin Häuser <mhaeuser@posteo.de> wrote:
> > ...
> >>>>>> 2) emit a GOT, which ends up being converted to PE/COFF Relocations (->
> >>>>>> self-relocation), for global data that cannot be referenced relatively?
> >>>>>> Is there any way to know/force that no symbol in GOT is accessed up
> >>>>>> until the end of the self-relocation process?
> >> Do you maybe have one final comment regarding that second question,
> >> please? :)
> > The RELA section is not converted into PE/COFF relocations. This would
> > not achieve a lot, given that no prior PE/COFF loader exists to
> > process them. There is a snippet of asm code in the startup code that
> > processes the R_AARCH64_RELATIVE relocation entries before calling
> > into C code.
>
> I searched for said ASM code till my fingers fell asleep and at last
> found this:
> https://github.com/tianocore/edk2/commit/b16fd231f6d8124fa05a0f086840934b8709faf9#diff-3d563cc4775c7720900f4895bf619eed06291044aaa277fcc57eddc7618351a1L12-R148
>
> If I understand the commit message correctly, it is basically "pray the
> C code does not use globals at all", which is fair enough, so maybe I
> should document this in my proposed new library? I trust that this is
> enough of a constraint for both ARM and AArch64, because I do not know
> them at all.
>

The C code can use globals, but not global pointer variables. But you
are right, this is not very robust at all.


> What worries me is that StandaloneMmCore has no such ASM entry point at
> all and instead it's just executing C directly. Also, it is not passed
> the "-fno-jump-tables" flag that is commented to be important in the
> commit linked above.
>

This is because the StandaloneMmCore is built with -fpie, which
already implies -fno-jump-tables, although I suppose this may not
offer complete coverage for BASE libraries that are pulled into the
link.


> Best regards,
> Marvin
>
> > This also gives us the guarantee that no GOT indirections are
> > dereferenced, given that our asm code simply does not do that.
> >
> >> Let's drop "GOT" and make it "any instruction that requires prior
> >> relocation to function correctly".
> >>
> > The thing to keep in mind here is that R_AARCH64_RELATIVE relocations
> > never target instructions, but only memory locations that carry
> > absolute addresses. This could be locations in .rodata or .data
> > (global vars carrying pointer values), or GOT entries.
> >
> >>>>> It is not really a GOT. Actually, a GOT is undesirable, as it forces
> >>>>> global variables to be referenced via an absolute address, even when a
> >>>>> relative reference could be used.
> >>>> Hmm, the GCC docs say a GOT is used for "all constant addresses" (I took
> >>>> it as "absolute"?), it is kind of vague. I understood it this way:
> >>>> 1) no-pie emits relocations that can target the .text and .data sections
> >>>> for instructions that embed and variables that hold an absolute address
> >>>> (I thought this was RELA?)
> >>>> 2) pie emits a GOT such that there are no relocations as described in
> >>>> 1), because all absolute addresses are indirected by GOT (just GOT
> >>>> references are relocated)
> >>>>
> >>> Correct. And this works really well for shared libraries, where all
> >>> text and data sections can be shared between processes, as they will
> >>> not be modified by the loader. All locations targeted by relocations
> >>> will be nicely lumped together in the GOT.
> >>>
> >>> However, for bare metal style programs, there is no sharing, and there
> >>> is no advantage to lumping anything together. It is much better to use
> >>> relative references where possible, and simply apply relocations
> >>> wherever needed across the text and data sections,
> >>>
> >>>> If I understood the process right, but the term (GOT) is wrong, sorry,
> >>>> that is what I gathered from the docs. :)
> >>>> I have a x86 + PE background, so ARM + ELF is a bit of a learning curve...
> >>>>
> >>> The GOT is a special data structure used for implicit variable
> >>> accesses, i.e., global vars used in the code. Statically initialized
> >>> pointer variables are the other category, which are not code, and for
> >>> which the same considerations do not apply, given that the right value
> >>> simply needs to be stored in the variable before the program starts.
> >>>
> >>>>> For instance, a statically initialized pointer always carries an
> >>>>> absolute address, and so it always needs an entry in the RELA table
> >>>>>
> >>>>> E.g.,
> >>>>>
> >>>>> int foo = 10; // external linkage
> >>>>> static int *bar = &foo;
> >>>>>
> >>>>> In this case, there is no way to use relative addressing because the
> >>>>> address of foo is taken at build time.
> >>>>>
> >>>>> However, if bar would be something like
> >>>>>
> >>>>> static int *bar() { return &foo; }
> >>>>>
> >>>>> the address is only taken at runtime, and the compiler can use a
> >>>>> relative reference instead, and no RELA entry is needed. With a GOT,
> >>>>> we force the compiler to allocate a variable that holds the absolute
> >>>>> address, which we would prefer to avoid.
> >>>> And this is not forced by whatever table -fpie uses, as per my
> >>>> understanding above?
> >>>>
> >>> The selection of 'code model' as it is called is controlled by GCC's
> >>> -mcmodel= argument, which defaults to 'small' on AArch64, regardless
> >>> of whether you use PIC/PIE or not.
> >> Aha, makes sense, thanks!
> >>
> >> Best regards,
> >> Marvin
> >>
> >>>>>>>> “Now, StandaloneMmPkg has similar (self-)relocation code too:https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386
> >>>>>>>>
> >>>>>>>> Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above.
> >>>>>>> No.
> >>>>>>>
> >>>>>>>> The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
> >>>>>>>>
> >>>>>>>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158
> >>>>>> As per your comments below, I think SecCore should not be located here.
> >>>>>> Is the Standalone MM core of *type* SecCore in the FFS (without *being*
> >>>>>> SecCore)? This confused me the most.
> >>>>>>
> >>>>> If the FFS SecCore section type is used here, it does not mean that
> >>>>> the image is a SEC image in the strict PI sense.
> >>>>>
> >>>>> Perhaps we were just too lazy to add a new type to the FFS spec?
> >>>> That is what I meant to imply with the middle question (well, not
> >>>> necessarily "lazy", for ARM there simply seems to not be any reason to
> >>>> distinguish if the environments are fully separate), just wanted to make
> >>>> sure I understand what the code does before modifying it.
> >>>>
> >>>> Thank you again!
> >>>>
> >>>> Best regards,
> >>>> Marvin
> >>>>
> >>>>>>>> “This yields the following questions to me:
> >>>>>>>>
> >>>>>>>> 1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
> >>>>>>>>
> >>>>>>> It is not spawned by the normal world code that runs UEFI. It is a
> >>>>>>> secure world component that runs in a completely different execution
> >>>>>>> context (TrustZone). The code does run with the MMU enabled from the
> >>>>>>> start, but running from an a priori fixed offset was considered to be
> >>>>>>> a security hazard, so we added self relocation support.
> >>>>>>>
> >>>>>>> The alternative would have been to add metadata to the StMmCore
> >>>>>>> component that can be interpreted by the secure world component that
> >>>>>>> loads it, but this would go beyond any existing specs, and make
> >>>>>>> portability more problematic.
> >>>>>>>
> >>>>>>>> 2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
> >>>>>>>>
> >>>>>>> No and no. Standalone MM has nothing to do with the code that runs as
> >>>>>>> part of UEFI itself. ArmPlatformPkg is completely separate from
> >>>>>>> StandaloneMmPkg.
> >>>>>>>
> >>>>>>>> 3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
> >>>>>>>>
> >>>>>>> SecCore contains a PE/COFF loader, so all subsequent modules are
> >>>>>>> loaded normally. This is similar to the ArmVirtQemuKernel
> >>>>>>> self-relocating SEC module, which only relocates itself in this
> >>>>>>> manner, and relies on standard PE/COFF metadata for loading other
> >>>>>>> modules.
> >>>>>> Interesting... this definitely is vastly different from the x86 side of
> >>>>>> things. I think most things became very clear. Thanks a lot!
> >>>>>>
> >>>>>>>> 4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”
> >>>>>>>>
> >>>>>>> trustedfirmware.org may have some useful documentation.
> >>>>>> I'll check it some time, hopefully this weekend. Thanks!
> >>>>>>
> >>>>> My pleasure.
>

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

* Re: [edk2-devel] ArmVirt and Self-Updating Code
  2021-08-01 16:33                     ` Ard Biesheuvel
@ 2021-08-01 21:40                       ` Marvin Häuser
  2021-08-02 18:05                         ` Andrew Fish
  0 siblings, 1 reply; 12+ messages in thread
From: Marvin Häuser @ 2021-08-01 21:40 UTC (permalink / raw)
  To: devel, ardb
  Cc: Bret Barkelew, Thomas Abraham, Ard Biesheuvel (TianoCore),
	Lindholm, Leif, Laszlo Ersek, Sami Mujawar, nd

01.08.2021 18:33:47 Ard Biesheuvel <ardb@kernel.org>:

> On Sat, 31 Jul 2021 at 21:08, Marvin Häuser <mhaeuser@posteo.de> wrote:
>> 
>> On 23.07.21 16:34, Ard Biesheuvel wrote:
>>> On Fri, 23 Jul 2021 at 16:27, Marvin Häuser <mhaeuser@posteo.de> 
>>> wrote:
>>>> 
>>>> 
>>>> On 23.07.21 16:09, Ard Biesheuvel wrote:
>>>>> On Fri, 23 Jul 2021 at 12:47, Marvin Häuser <mhaeuser@posteo.de> 
>>>>> wrote:
>>>>>> …
>>> ...
>>>>>> …
>>>> Do you maybe have one final comment regarding that second question,
>>>> please? :)
>>> The RELA section is not converted into PE/COFF relocations. This 
>>> would
>>> not achieve a lot, given that no prior PE/COFF loader exists to
>>> process them. There is a snippet of asm code in the startup code that
>>> processes the R_AARCH64_RELATIVE relocation entries before calling
>>> into C code.
>> 
>> I searched for said ASM code till my fingers fell asleep and at last
>> found this:
>> https://github.com/tianocore/edk2/commit/b16fd231f6d8124fa05a0f086840934b8709faf9#diff-3d563cc4775c7720900f4895bf619eed06291044aaa277fcc57eddc7618351a1L12-R148
>> 
>> If I understand the commit message correctly, it is basically "pray 
>> the
>> C code does not use globals at all", which is fair enough, so maybe I
>> should document this in my proposed new library? I trust that this is
>> enough of a constraint for both ARM and AArch64, because I do not know
>> them at all.
>> 
> 
> The C code can use globals, but not global pointer variables. But you
> are right, this is not very robust at all.

Right... Will document for my PE library.

>> What worries me is that StandaloneMmCore has no such ASM entry point 
>> at
>> all and instead it's just executing C directly. Also, it is not passed
>> the "-fno-jump-tables" flag that is commented to be important in the
>> commit linked above.
>> 
> 
> This is because the StandaloneMmCore is built with -fpie, which
> already implies -fno-jump-tables, although I suppose this may not
> offer complete coverage for BASE libraries that are pulled into the
> link.

Ah okay, thanks. Out of curiosity of how ARM implements PIE, and how 
StMmCore self-relocation can work *after* the PE/COFF section 
permissions have been applied with .got merged into .text (i.e. 
read-only), I checked the GCC5 "DLL" with readelf and found many 
relocations into the .text section. I have no idea how any of this 
works, and no idea where to find out, but as it apparently does, I might 
just update the PE calls and call it a day. I cannot test anything 
either because there is no QEMU code for StMmCore I can find. :(

Thanks for your tireless replies!

Best regards,
Marvin

> 
> 
>> Best regards,
>> Marvin
>> 
>>> This also gives us the guarantee that no GOT indirections are
>>> dereferenced, given that our asm code simply does not do that.
>>> 
>>>> Let's drop "GOT" and make it "any instruction that requires prior
>>>> relocation to function correctly".
>>>> 
>>> The thing to keep in mind here is that R_AARCH64_RELATIVE relocations
>>> never target instructions, but only memory locations that carry
>>> absolute addresses. This could be locations in .rodata or .data
>>> (global vars carrying pointer values), or GOT entries.
>>> 
>>>>>> …
>>>>> Correct. And this works really well for shared libraries, where all
>>>>> text and data sections can be shared between processes, as they 
>>>>> will
>>>>> not be modified by the loader. All locations targeted by 
>>>>> relocations
>>>>> will be nicely lumped together in the GOT.
>>>>> 
>>>>> However, for bare metal style programs, there is no sharing, and 
>>>>> there
>>>>> is no advantage to lumping anything together. It is much better to 
>>>>> use
>>>>> relative references where possible, and simply apply relocations
>>>>> wherever needed across the text and data sections,
>>>>> 
>>>>>> …
>>>>> The GOT is a special data structure used for implicit variable
>>>>> accesses, i.e., global vars used in the code. Statically 
>>>>> initialized
>>>>> pointer variables are the other category, which are not code, and 
>>>>> for
>>>>> which the same considerations do not apply, given that the right 
>>>>> value
>>>>> simply needs to be stored in the variable before the program 
>>>>> starts.
>>>>> 
>>>>>> …
>>>>> The selection of 'code model' as it is called is controlled by 
>>>>> GCC's
>>>>> -mcmodel= argument, which defaults to 'small' on AArch64, 
>>>>> regardless
>>>>> of whether you use PIC/PIE or not.
>>>> Aha, makes sense, thanks!
>>>> 
>>>> Best regards,
>>>> Marvin
>>>> 
>>>>>> …
>> 
> 
> 
> 


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

* Re: [edk2-devel] ArmVirt and Self-Updating Code
  2021-08-01 21:40                       ` [edk2-devel] " Marvin Häuser
@ 2021-08-02 18:05                         ` Andrew Fish
  0 siblings, 0 replies; 12+ messages in thread
From: Andrew Fish @ 2021-08-02 18:05 UTC (permalink / raw)
  To: edk2-devel-groups-io, Marvin Häuser
  Cc: Ard Biesheuvel, Bret Barkelew, Thomas Abraham,
	Ard Biesheuvel (TianoCore), Lindholm, Leif, Laszlo Ersek,
	Sami Mujawar, nd



> On Aug 1, 2021, at 2:40 PM, Marvin Häuser <mhaeuser@posteo.de> wrote:
> 
> 01.08.2021 18:33:47 Ard Biesheuvel <ardb@kernel.org>:
> 
>> On Sat, 31 Jul 2021 at 21:08, Marvin Häuser <mhaeuser@posteo.de> wrote:
>>> On 23.07.21 16:34, Ard Biesheuvel wrote:
>>>> On Fri, 23 Jul 2021 at 16:27, Marvin Häuser <mhaeuser@posteo.de> wrote:
>>>>> On 23.07.21 16:09, Ard Biesheuvel wrote:
>>>>>> On Fri, 23 Jul 2021 at 12:47, Marvin Häuser <mhaeuser@posteo.de> wrote:
>>>>>>> …
>>>> ...
>>>>>>> …
>>>>> Do you maybe have one final comment regarding that second question,
>>>>> please? :)
>>>> The RELA section is not converted into PE/COFF relocations. This would
>>>> not achieve a lot, given that no prior PE/COFF loader exists to
>>>> process them. There is a snippet of asm code in the startup code that
>>>> processes the R_AARCH64_RELATIVE relocation entries before calling
>>>> into C code.
>>> I searched for said ASM code till my fingers fell asleep and at last
>>> found this:
>>> https://github.com/tianocore/edk2/commit/b16fd231f6d8124fa05a0f086840934b8709faf9#diff-3d563cc4775c7720900f4895bf619eed06291044aaa277fcc57eddc7618351a1L12-R148
>>> If I understand the commit message correctly, it is basically "pray the
>>> C code does not use globals at all", which is fair enough, so maybe I
>>> should document this in my proposed new library? I trust that this is
>>> enough of a constraint for both ARM and AArch64, because I do not know
>>> them at all.
>> The C code can use globals, but not global pointer variables. But you
>> are right, this is not very robust at all.
> 
> Right... Will document for my PE library.
> 
>>> What worries me is that StandaloneMmCore has no such ASM entry point at
>>> all and instead it's just executing C directly. Also, it is not passed
>>> the "-fno-jump-tables" flag that is commented to be important in the
>>> commit linked above.
>> This is because the StandaloneMmCore is built with -fpie, which
>> already implies -fno-jump-tables, although I suppose this may not
>> offer complete coverage for BASE libraries that are pulled into the
>> link.
> 
> Ah okay, thanks. Out of curiosity of how ARM implements PIE, and how StMmCore self-relocation can work *after* the PE/COFF section permissions have been applied with .got merged into .text (i.e. read-only), I checked the GCC5 "DLL" with readelf and found many relocations into the .text section. I have no idea how any of this works, and no idea where to find out, but as it apparently does, I might just update the PE calls and call it a day. I cannot test anything either because there is no QEMU code for StMmCore I can find. :(
> 

Marvin,

It is useful to remember that there are object file (resolved by the linker), dynamic loading (resolved when the DLL is bound at runtime), and image relocations. In the EFI PE/COFF we only end up with the image relocations that need to be processed when an image is loaded into memory. I seem to remember seeing the other classes of relocations still being present in the ELF files, but they end up being a no-opt for EFI. You can look at the EFI PE/COFF relocations to see the things EFI cares about. 

Side note… The Xcode/clang toolchain requires the TEXT section to not contain relocations for X64, and the linker will fail if there is code that requires a relocation in the text section. This generally is not a problem, but hand coded assembler can trigger a link failure that is specific to Xcode. 

Thanks,

Andrew Fish

> Thanks for your tireless replies!
> 
> Best regards,
> Marvin
> 
>>> Best regards,
>>> Marvin
>>>> This also gives us the guarantee that no GOT indirections are
>>>> dereferenced, given that our asm code simply does not do that.
>>>>> Let's drop "GOT" and make it "any instruction that requires prior
>>>>> relocation to function correctly".
>>>> The thing to keep in mind here is that R_AARCH64_RELATIVE relocations
>>>> never target instructions, but only memory locations that carry
>>>> absolute addresses. This could be locations in .rodata or .data
>>>> (global vars carrying pointer values), or GOT entries.
>>>>>>> …
>>>>>> Correct. And this works really well for shared libraries, where all
>>>>>> text and data sections can be shared between processes, as they will
>>>>>> not be modified by the loader. All locations targeted by relocations
>>>>>> will be nicely lumped together in the GOT.
>>>>>> However, for bare metal style programs, there is no sharing, and there
>>>>>> is no advantage to lumping anything together. It is much better to use
>>>>>> relative references where possible, and simply apply relocations
>>>>>> wherever needed across the text and data sections,
>>>>>>> …
>>>>>> The GOT is a special data structure used for implicit variable
>>>>>> accesses, i.e., global vars used in the code. Statically initialized
>>>>>> pointer variables are the other category, which are not code, and for
>>>>>> which the same considerations do not apply, given that the right value
>>>>>> simply needs to be stored in the variable before the program starts.
>>>>>>> …
>>>>>> The selection of 'code model' as it is called is controlled by GCC's
>>>>>> -mcmodel= argument, which defaults to 'small' on AArch64, regardless
>>>>>> of whether you use PIC/PIE or not.
>>>>> Aha, makes sense, thanks!
>>>>> Best regards,
>>>>> Marvin
>>>>>>> …
> 
> 
> 
> 
> 
> 


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

end of thread, other threads:[~2021-08-02 18:05 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <MW4PR21MB19074D9D114BBBCC21B53B6FEF199@MW4PR21MB1907.namprd21.prod.outlook.com>
     [not found] ` <DB9PR08MB67464B261E4F1815BCDD7C289D199@DB9PR08MB6746.eurprd08.prod.outlook.com>
2021-07-22 14:54   ` ArmVirt and Self-Updating Code Bret Barkelew
2021-07-22 15:14     ` Ard Biesheuvel
2021-07-23  9:54       ` Marvin Häuser
2021-07-23 10:13         ` Ard Biesheuvel
2021-07-23 10:47           ` Marvin Häuser
2021-07-23 14:09             ` Ard Biesheuvel
2021-07-23 14:27               ` Marvin Häuser
2021-07-23 14:34                 ` Ard Biesheuvel
2021-07-31 19:08                   ` Marvin Häuser
2021-08-01 16:33                     ` Ard Biesheuvel
2021-08-01 21:40                       ` [edk2-devel] " Marvin Häuser
2021-08-02 18:05                         ` Andrew Fish

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