From: "Taylor Beebe" <t@taylorbeebe.com>
To: Ard Biesheuvel <ardb@kernel.org>, devel@edk2.groups.io
Cc: Michael Kinney <michael.d.kinney@intel.com>,
Liming Gao <gaoliming@byosoft.com.cn>,
Jiewen Yao <jiewen.yao@intel.com>,
Michael Kubacki <michael.kubacki@microsoft.com>,
Sean Brogan <sean.brogan@microsoft.com>,
Rebecca Cran <quic_rcran@quicinc.com>,
Leif Lindholm <quic_llindhol@quicinc.com>,
Sami Mujawar <sami.mujawar@arm.com>
Subject: Re: [edk2-devel] [PATCH 4/4] ArmPkg/CpuDxe: Implement EFI memory attributes protocol
Date: Fri, 3 Feb 2023 11:08:58 -0800 [thread overview]
Message-ID: <db7c3126-2741-d1dc-0ed9-6690a432724f@taylorbeebe.com> (raw)
In-Reply-To: <CAMj1kXEZkLNB8XeMqbZwMVLneccaHak7G39Zymd-RT7M=oP3jg@mail.gmail.com>
On 2/2/2023 1:43 AM, Ard Biesheuvel wrote:
> On Wed, 1 Feb 2023 at 19:41, Taylor Beebe <t@taylorbeebe.com> wrote:
>>
>> Hey Ard,
>>
>> Have you encountered complications which stem from the lack of
>> pre-allocated page table memory on ARM devices utilizing the memory
>> protection policy?
>>
>
> Interesting. No I haven't, but I agree it is a potential concern.
>
>> My observation is the call stack can end up something like:
>>
>> 1. MemoryAttributeProtocol->SetMemoryAttributes(EFI_MEMORY_RO)
>> 2. ArmSetMemoryRegionReadOnly ()
>> 3. SetMemoryRegionAttribute()
>> 4. UpdateRegionMapping()
>> 5. UpdateRegionMappingRecursive()
>> 6. AllocatePages() -> Need memory for a translation table entry
>> 7. CoreAllocatePages()
>> 8. ApplyMemoryProtectionPolicy() -> Policy says new page should be XN
>> 9. gCpu->SetMemoryAttributes()
>> 10. Back to 3 and loop infinitely
>>
>
> So one thing that makes this scenario unlikely (I think) is that by
> default, all unallocated space has the XP attribute set already, and
> so allocating a page table with XP attributes should not result in the
> need for a block entry split, and therefore no allocation for a next
> level table. Perhaps we need some asserts to diagnose this at runtime?
Ah yes, you're right. On Project Mu, we make an explicit check to the
attributes of the region in ApplyMemoryProtectionPolicy() to determine
if the attributes need to be updated. We do this to account for the
introduction of the memory attribute protocol and to mitigate a rare
issue where an allocation might not have consistent attributes when
allocating a type other than BootServicesData. This change to
ApplyMemoryProtectionPolicy() means an infinite loop is possible during
the memory protection initialization phase.
>
>> On 1/31/2023 2:35 PM, Ard Biesheuvel wrote:
>>> Expose the protocol introduced in v2.10 that permits the caller to
>>> manage mapping permissions in the page tables.
>>>
>>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>>> ---
>>> ArmPkg/Drivers/CpuDxe/CpuDxe.c | 2 +
>>> ArmPkg/Drivers/CpuDxe/CpuDxe.h | 3 +
>>> ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 2 +
>>> ArmPkg/Drivers/CpuDxe/MemoryAttribute.c | 242 ++++++++++++++++++++
>>> 4 files changed, 249 insertions(+)
>>>
>>> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>>> index e6742f0a25fc..d04958e79e52 100644
>>> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>>> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>>> @@ -244,6 +244,8 @@ CpuDxeInitialize (
>>> &mCpuHandle,
>>>
>>> &gEfiCpuArchProtocolGuid,
>>>
>>> &mCpu,
>>>
>>> + &gEfiMemoryAttributeProtocolGuid,
>>>
>>> + &mMemoryAttribute,
>>>
>>> NULL
>>>
>>> );
>>>
>>>
>>>
>>> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
>>> index 8933fa90c4ed..f45d2bc101a3 100644
>>> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h
>>> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
>>> @@ -30,9 +30,12 @@
>>> #include <Protocol/Cpu.h>
>>>
>>> #include <Protocol/DebugSupport.h>
>>>
>>> #include <Protocol/LoadedImage.h>
>>>
>>> +#include <Protocol/MemoryAttribute.h>
>>>
>>>
>>>
>>> extern BOOLEAN mIsFlushingGCD;
>>>
>>>
>>>
>>> +extern EFI_MEMORY_ATTRIBUTE_PROTOCOL mMemoryAttribute;
>>>
>>> +
>>>
>>> /**
>>>
>>> This function registers and enables the handler specified by InterruptHandler for a processor
>>>
>>> interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
>>>
>>> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
>>> index 10792b393fc8..e732e21cb94a 100644
>>> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
>>> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
>>> @@ -23,6 +23,7 @@ [Sources.Common]
>>> CpuDxe.h
>>>
>>> CpuMmuCommon.c
>>>
>>> Exception.c
>>>
>>> + MemoryAttribute.c
>>>
>>>
>>>
>>> [Sources.ARM]
>>>
>>> Arm/Mmu.c
>>>
>>> @@ -53,6 +54,7 @@ [LibraryClasses]
>>>
>>>
>>> [Protocols]
>>>
>>> gEfiCpuArchProtocolGuid
>>>
>>> + gEfiMemoryAttributeProtocolGuid
>>>
>>>
>>>
>>> [Guids]
>>>
>>> gEfiDebugImageInfoTableGuid
>>>
>>> diff --git a/ArmPkg/Drivers/CpuDxe/MemoryAttribute.c b/ArmPkg/Drivers/CpuDxe/MemoryAttribute.c
>>> new file mode 100644
>>> index 000000000000..9aeb83fff1b9
>>> --- /dev/null
>>> +++ b/ArmPkg/Drivers/CpuDxe/MemoryAttribute.c
>>> @@ -0,0 +1,242 @@
>>> +/** @file
>>>
>>> +
>>>
>>> + Copyright (c) 2023, Google LLC. All rights reserved.
>>>
>>> +
>>>
>>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>>>
>>> +
>>>
>>> +**/
>>>
>>> +
>>>
>>> +#include "CpuDxe.h"
>>>
>>> +
>>>
>>> +/**
>>>
>>> + This function retrieves the attributes of the memory region specified by
>>>
>>> + BaseAddress and Length. If different attributes are got from different part
>>>
>>> + of the memory region, EFI_NO_MAPPING will be returned.
>>>
>>> +
>>>
>>> + @param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
>>>
>>> + @param BaseAddress The physical address that is the start address of
>>>
>>> + a memory region.
>>>
>>> + @param Length The size in bytes of the memory region.
>>>
>>> + @param Attributes Pointer to attributes returned.
>>>
>>> +
>>>
>>> + @retval EFI_SUCCESS The attributes got for the memory region.
>>>
>>> + @retval EFI_INVALID_PARAMETER Length is zero.
>>>
>>> + Attributes is NULL.
>>>
>>> + @retval EFI_NO_MAPPING Attributes are not consistent cross the memory
>>>
>>> + region.
>>>
>>> + @retval EFI_UNSUPPORTED The processor does not support one or more
>>>
>>> + bytes of the memory resource range specified
>>>
>>> + by BaseAddress and Length.
>>>
>>> +
>>>
>>> +**/
>>>
>>> +STATIC
>>>
>>> +EFI_STATUS
>>>
>>> +GetMemoryAttributes (
>>>
>>> + IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
>>>
>>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>>
>>> + IN UINT64 Length,
>>>
>>> + OUT UINT64 *Attributes
>>>
>>> + )
>>>
>>> +{
>>>
>>> + UINTN RegionAddress;
>>>
>>> + UINTN RegionLength;
>>>
>>> + UINTN RegionAttributes;
>>>
>>> + UINTN Union;
>>>
>>> + UINTN Intersection;
>>>
>>> + EFI_STATUS Status;
>>>
>>> +
>>>
>>> + if ((Length == 0) || (Attributes == NULL)) {
>>>
>>> + return EFI_INVALID_PARAMETER;
>>>
>>> + }
>>>
>>> +
>>>
>>> + DEBUG ((DEBUG_INFO,
>>>
>>> + "%a: BaseAddress == 0x%lx, Length == 0x%lx\n",
>>>
>>> + __FUNCTION__,
>>>
>>> + (UINTN)BaseAddress,
>>>
>>> + (UINTN)Length
>>>
>>> + ));
>>>
>>> +
>>>
>>> + Union = 0;
>>>
>>> + Intersection = MAX_UINTN;
>>>
>>> +
>>>
>>> + for (RegionAddress = (UINTN)BaseAddress;
>>>
>>> + RegionAddress < (UINTN)(BaseAddress + Length);
>>>
>>> + RegionAddress += RegionLength) {
>>>
>>> +
>>>
>>> + Status = GetMemoryRegion (&RegionAddress,
>>>
>>> + &RegionLength,
>>>
>>> + &RegionAttributes
>>>
>>> + );
>>>
>>> +
>>>
>>> + DEBUG ((DEBUG_INFO,
>>>
>>> + "%a: RegionAddress == 0x%lx, RegionLength == 0x%lx, RegionAttributes == 0x%lx\n",
>>>
>>> + __FUNCTION__,
>>>
>>> + RegionAddress,
>>>
>>> + RegionLength,
>>>
>>> + RegionAttributes
>>>
>>> + ));
>>>
>>> +
>>>
>>> + if (EFI_ERROR (Status)) {
>>>
>>> + return EFI_NO_MAPPING;
>>>
>>> + }
>>>
>>> +
>>>
>>> + Union |= RegionAttributes;
>>>
>>> + Intersection &= RegionAttributes;
>>>
>>> + }
>>>
>>> +
>>>
>>> + DEBUG ((DEBUG_INFO,
>>>
>>> + "%a: Union == %lx, Intersection == %lx\n",
>>>
>>> + __FUNCTION__,
>>>
>>> + Union,
>>>
>>> + Intersection
>>>
>>> + ));
>>>
>>> +
>>>
>>> + if (Union != Intersection) {
>>>
>>> + return EFI_NO_MAPPING;
>>>
>>> + }
>>>
>>> +
>>>
>>> + *Attributes = PageAttributeToGcdAttribute (Union) & (EFI_MEMORY_RO | EFI_MEMORY_XP);
>>>
>>> + return EFI_SUCCESS;
>>>
>>> +}
>>>
>>> +
>>>
>>> +/**
>>>
>>> + This function set given attributes of the memory region specified by
>>>
>>> + BaseAddress and Length.
>>>
>>> +
>>>
>>> + The valid Attributes is EFI_MEMORY_RP, EFI_MEMORY_XP, and EFI_MEMORY_RO.
>>>
>>> +
>>>
>>> + @param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
>>>
>>> + @param BaseAddress The physical address that is the start address of
>>>
>>> + a memory region.
>>>
>>> + @param Length The size in bytes of the memory region.
>>>
>>> + @param Attributes The bit mask of attributes to set for the memory
>>>
>>> + region.
>>>
>>> +
>>>
>>> + @retval EFI_SUCCESS The attributes were set for the memory region.
>>>
>>> + @retval EFI_INVALID_PARAMETER Length is zero.
>>>
>>> + Attributes specified an illegal combination of
>>>
>>> + attributes that cannot be set together.
>>>
>>> + @retval EFI_UNSUPPORTED The processor does not support one or more
>>>
>>> + bytes of the memory resource range specified
>>>
>>> + by BaseAddress and Length.
>>>
>>> + The bit mask of attributes is not supported for
>>>
>>> + the memory resource range specified by
>>>
>>> + BaseAddress and Length.
>>>
>>> +
>>>
>>> +**/
>>>
>>> +STATIC
>>>
>>> +EFI_STATUS
>>>
>>> +SetMemoryAttributes (
>>>
>>> + IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
>>>
>>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>>
>>> + IN UINT64 Length,
>>>
>>> + IN UINT64 Attributes
>>>
>>> + )
>>>
>>> +{
>>>
>>> + EFI_STATUS Status;
>>>
>>> +
>>>
>>> + DEBUG ((DEBUG_INFO,
>>>
>>> + "%a: BaseAddress == 0x%lx, Length == 0x%lx, Attributes == 0x%lx\n",
>>>
>>> + __FUNCTION__,
>>>
>>> + (UINTN)BaseAddress,
>>>
>>> + (UINTN)Length,
>>>
>>> + (UINTN)Attributes
>>>
>>> + ));
>>>
>>> +
>>>
>>> + if ((Length == 0) ||
>>>
>>> + ((Attributes & ~(EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP)) != 0)) {
>>>
>>> + return EFI_INVALID_PARAMETER;
>>>
>>> + }
>>>
>>> +
>>>
>>> + if ((Attributes & EFI_MEMORY_RP) != 0) {
>>>
>>> + return EFI_UNSUPPORTED;
>>>
>>> + }
>>>
>>> +
>>>
>>> + if ((Attributes & EFI_MEMORY_RO) != 0) {
>>>
>>> + Status = ArmSetMemoryRegionReadOnly (BaseAddress, Length);
>>>
>>> + if (EFI_ERROR (Status)) {
>>>
>>> + return EFI_UNSUPPORTED;
>>>
>>> + }
>>>
>>> + }
>>>
>>> +
>>>
>>> + if ((Attributes & EFI_MEMORY_XP) != 0) {
>>>
>>> + Status = ArmSetMemoryRegionNoExec (BaseAddress, Length);
>>>
>>> + if (EFI_ERROR (Status)) {
>>>
>>> + return EFI_UNSUPPORTED;
>>>
>>> + }
>>>
>>> + }
>>>
>>> +
>>>
>>> + return EFI_SUCCESS;
>>>
>>> +}
>>>
>>> +
>>>
>>> +/**
>>>
>>> + This function clears given attributes of the memory region specified by
>>>
>>> + BaseAddress and Length.
>>>
>>> +
>>>
>>> + The valid Attributes is EFI_MEMORY_RP, EFI_MEMORY_XP, and EFI_MEMORY_RO.
>>>
>>> +
>>>
>>> + @param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
>>>
>>> + @param BaseAddress The physical address that is the start address of
>>>
>>> + a memory region.
>>>
>>> + @param Length The size in bytes of the memory region.
>>>
>>> + @param Attributes The bit mask of attributes to clear for the memory
>>>
>>> + region.
>>>
>>> +
>>>
>>> + @retval EFI_SUCCESS The attributes were cleared for the memory region.
>>>
>>> + @retval EFI_INVALID_PARAMETER Length is zero.
>>>
>>> + Attributes specified an illegal combination of
>>>
>>> + attributes that cannot be cleared together.
>>>
>>> + @retval EFI_UNSUPPORTED The processor does not support one or more
>>>
>>> + bytes of the memory resource range specified
>>>
>>> + by BaseAddress and Length.
>>>
>>> + The bit mask of attributes is not supported for
>>>
>>> + the memory resource range specified by
>>>
>>> + BaseAddress and Length.
>>>
>>> +
>>>
>>> +**/
>>>
>>> +STATIC
>>>
>>> +EFI_STATUS
>>>
>>> +ClearMemoryAttributes (
>>>
>>> + IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
>>>
>>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>>
>>> + IN UINT64 Length,
>>>
>>> + IN UINT64 Attributes
>>>
>>> + )
>>>
>>> +{
>>>
>>> + EFI_STATUS Status;
>>>
>>> +
>>>
>>> + DEBUG ((DEBUG_INFO,
>>>
>>> + "%a: BaseAddress == 0x%lx, Length == 0x%lx, Attributes == 0x%lx\n",
>>>
>>> + __FUNCTION__,
>>>
>>> + (UINTN)BaseAddress,
>>>
>>> + (UINTN)Length,
>>>
>>> + (UINTN)Attributes
>>>
>>> + ));
>>>
>>> +
>>>
>>> + if ((Length == 0) ||
>>>
>>> + ((Attributes & ~(EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP)) != 0)) {
>>>
>>> + return EFI_INVALID_PARAMETER;
>>>
>>> + }
>>>
>>> +
>>>
>>> + if ((Attributes & EFI_MEMORY_RO) != 0) {
>>>
>>> + Status = ArmClearMemoryRegionReadOnly (BaseAddress, Length);
>>>
>>> + if (EFI_ERROR (Status)) {
>>>
>>> + return EFI_UNSUPPORTED;
>>>
>>> + }
>>>
>>> + }
>>>
>>> +
>>>
>>> + if ((Attributes & EFI_MEMORY_XP) != 0) {
>>>
>>> + Status = ArmClearMemoryRegionNoExec (BaseAddress, Length);
>>>
>>> + if (EFI_ERROR (Status)) {
>>>
>>> + return EFI_UNSUPPORTED;
>>>
>>> + }
>>>
>>> + }
>>>
>>> +
>>>
>>> + return EFI_SUCCESS;
>>>
>>> +}
>>>
>>> +
>>>
>>> +EFI_MEMORY_ATTRIBUTE_PROTOCOL mMemoryAttribute = {
>>>
>>> + GetMemoryAttributes,
>>>
>>> + SetMemoryAttributes,
>>>
>>> + ClearMemoryAttributes
>>>
>>> +};
>>>
>>
>> --
>> Taylor Beebe
>> Software Engineer @ Microsoft
>>
>>
>>
>>
>>
--
Taylor Beebe
Software Engineer @ Microsoft
next prev parent reply other threads:[~2023-02-03 19:09 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-31 22:35 [PATCH 0/4] ArmPkg: implement EFI memory attributes protocol Ard Biesheuvel
2023-01-31 22:35 ` [PATCH 1/4] MdePkg: Add Memory Attribute Protocol definition Ard Biesheuvel
2023-02-02 3:19 ` 回复: " gaoliming
2023-02-02 9:25 ` [edk2-devel] " Ard Biesheuvel
2023-01-31 22:35 ` [PATCH 2/4] MdePkg: Bump implemented UEFI version to v2.10 Ard Biesheuvel
2023-02-01 0:10 ` Michael D Kinney
2023-02-01 7:54 ` Ard Biesheuvel
2023-01-31 22:35 ` [PATCH 3/4] ArmPkg/CpuDxe: Unify PageAttributeToGcdAttribute helper Ard Biesheuvel
2023-01-31 22:35 ` [PATCH 4/4] ArmPkg/CpuDxe: Implement EFI memory attributes protocol Ard Biesheuvel
2023-02-01 18:41 ` [edk2-devel] " Taylor Beebe
2023-02-02 9:43 ` Ard Biesheuvel
2023-02-03 19:08 ` Taylor Beebe [this message]
2023-02-03 19:58 ` Marvin Häuser
2023-02-07 1:18 ` Taylor Beebe
2023-02-07 8:29 ` Ard Biesheuvel
2023-02-07 8:56 ` Marvin Häuser
2023-02-07 9:16 ` Ard Biesheuvel
2023-02-07 10:00 ` Marvin Häuser
2023-02-07 10:01 ` Ard Biesheuvel
2023-02-07 10:13 ` Marvin Häuser
2023-02-07 17:56 ` Ard Biesheuvel
2023-02-07 18:19 ` Taylor Beebe
2023-02-07 18:50 ` Marvin Häuser
2023-02-07 18:19 ` Marvin Häuser
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=db7c3126-2741-d1dc-0ed9-6690a432724f@taylorbeebe.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox