public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
To: Leif Lindholm <leif.lindholm@linaro.org>
Cc: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
	Laszlo Ersek <lersek@redhat.com>
Subject: Re: [PATCH v2 2/4] ArmPkg/CpuDxe ARM: avoid unnecessary cache/TLB maintenance
Date: Mon, 6 Mar 2017 16:06:07 +0100	[thread overview]
Message-ID: <CAKv+Gu_Cy4fUiRhf0vtFihb33dLvWsWqV3VOZZMCsw2Jn=h_nA@mail.gmail.com> (raw)
In-Reply-To: <20170306142759.GU16034@bivouac.eciton.net>

On 6 March 2017 at 15:27, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Thu, Mar 02, 2017 at 10:36:14AM +0000, Ard Biesheuvel wrote:
>> Page and section entries in the page tables are updated using the
>> helper ArmUpdateTranslationTableEntry(), which cleans the page
>> table entry to the PoC, and invalidates the TLB entry covering
>> the page described by the entry being updated.
>>
>> Since we may be updating section entries, we might be leaving stale
>> TLB entries at this point (for all pages in the section except the
>> first one), which will be invalidated wholesale at the end of
>> SetMemoryAttributes(). At that point, all caches are cleaned *and*
>> invalidated as well.
>>
>> This cache maintenance is costly and unnecessary. The TLB maintenance
>> is only necessary if we updated any section entries, since any page
>> by page entries that have been updated will have been invalidated
>> individually by ArmUpdateTranslationTableEntry().
>>
>> So drop the clean/invalidate of the caches, and only perform the
>> full TLB flush if UpdateSectionEntries() was called, or if sections
>> were split by UpdatePageEntries(). Finally, make the cache maintenance
>> on the remapped regions themselves conditional on whether any memory
>> type attributes were modified.
>>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> ---
>>  ArmPkg/Drivers/CpuDxe/Arm/Mmu.c | 60 +++++++++++---------
>>  1 file changed, 34 insertions(+), 26 deletions(-)
>>
>> diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
>> index ce4d529bda67..26b637e7658f 100644
>> --- a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
>> +++ b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
>> @@ -347,10 +347,11 @@ SyncCacheConfig (
>>
>>  EFI_STATUS
>>  UpdatePageEntries (
>> -  IN EFI_PHYSICAL_ADDRESS      BaseAddress,
>> -  IN UINT64                    Length,
>> -  IN UINT64                    Attributes,
>> -  IN EFI_PHYSICAL_ADDRESS      VirtualMask
>> +  IN  EFI_PHYSICAL_ADDRESS      BaseAddress,
>> +  IN  UINT64                    Length,
>> +  IN  UINT64                    Attributes,
>> +  IN  EFI_PHYSICAL_ADDRESS      VirtualMask,
>> +  OUT BOOLEAN                   *FlushTlbs
>>    )
>>  {
>>    EFI_STATUS    Status;
>> @@ -446,6 +447,9 @@ UpdatePageEntries (
>>
>>        // Re-read descriptor
>>        Descriptor = FirstLevelTable[FirstLevelIdx];
>> +      if (FlushTlbs != NULL) {
>
> If FlushTlbs is optional, should it not be marked OPTIONAL above?

Yes

> If you fold that in:
> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
>

Thanks

>> +        *FlushTlbs = TRUE;
>> +      }
>>      }
>>
>>      // Obtain page table base address
>> @@ -471,15 +475,16 @@ UpdatePageEntries (
>>
>>      if (CurrentPageTableEntry  != PageTableEntry) {
>>        Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));
>> -      if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {
>> -        // The current section mapping is cacheable so Clean/Invalidate the MVA of the page
>> -        // Note assumes switch(Attributes), not ARMv7 possibilities
>> -        WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);
>> -      }
>>
>>        // Only need to update if we are changing the entry
>>        PageTable[PageTableIndex] = PageTableEntry;
>>        ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva);
>> +
>> +      // Clean/invalidate the cache for this page, but only
>> +      // if we are modifying the memory type attributes
>> +      if (((CurrentPageTableEntry ^ PageTableEntry) & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) != 0) {
>> +        WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);
>> +      }
>>      }
>>
>>      Status = EFI_SUCCESS;
>> @@ -581,7 +586,12 @@ UpdateSectionEntries (
>>      // has this descriptor already been coverted to pages?
>>      if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) {
>>        // forward this 1MB range to page table function instead
>> -      Status = UpdatePageEntries ((FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT, TT_DESCRIPTOR_SECTION_SIZE, Attributes, VirtualMask);
>> +      Status = UpdatePageEntries (
>> +                 (FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT,
>> +                 TT_DESCRIPTOR_SECTION_SIZE,
>> +                 Attributes,
>> +                 VirtualMask,
>> +                 NULL);
>>      } else {
>>        // still a section entry
>>
>> @@ -596,15 +606,16 @@ UpdateSectionEntries (
>>
>>        if (CurrentDescriptor  != Descriptor) {
>>          Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
>> -        if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {
>> -          // The current section mapping is cacheable so Clean/Invalidate the MVA of the section
>> -          // Note assumes switch(Attributes), not ARMv7 possabilities
>> -          WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);
>> -        }
>>
>>          // Only need to update if we are changing the descriptor
>>          FirstLevelTable[FirstLevelIdx + i] = Descriptor;
>>          ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva);
>> +
>> +        // Clean/invalidate the cache for this section, but only
>> +        // if we are modifying the memory type attributes
>> +        if (((CurrentDescriptor ^ Descriptor) & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) != 0) {
>> +          WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);
>> +        }
>>        }
>>
>>        Status = EFI_SUCCESS;
>> @@ -680,6 +691,7 @@ SetMemoryAttributes (
>>  {
>>    EFI_STATUS    Status;
>>    UINT64        ChunkLength;
>> +  BOOLEAN       FlushTlbs;
>>
>>    //
>>    // Ignore invocations that only modify permission bits
>> @@ -688,6 +700,7 @@ SetMemoryAttributes (
>>      return EFI_SUCCESS;
>>    }
>>
>> +  FlushTlbs = FALSE;
>>    while (Length > 0) {
>>      if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) &&
>>          Length >= TT_DESCRIPTOR_SECTION_SIZE) {
>> @@ -700,6 +713,8 @@ SetMemoryAttributes (
>>
>>        Status = UpdateSectionEntries (BaseAddress, ChunkLength, Attributes,
>>                   VirtualMask);
>> +
>> +      FlushTlbs = TRUE;
>>      } else {
>>
>>        //
>> @@ -717,7 +732,7 @@ SetMemoryAttributes (
>>          BaseAddress, ChunkLength, Attributes));
>>
>>        Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
>> -                 VirtualMask);
>> +                 VirtualMask, &FlushTlbs);
>>      }
>>
>>      if (EFI_ERROR (Status)) {
>> @@ -728,16 +743,9 @@ SetMemoryAttributes (
>>      Length -= ChunkLength;
>>    }
>>
>> -  // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks
>> -  // flush and invalidate pages
>> -  //TODO: Do we really need to invalidate the caches everytime we change the memory attributes ?
>> -  ArmCleanInvalidateDataCache ();
>> -
>> -  ArmInvalidateInstructionCache ();
>> -
>> -  // Invalidate all TLB entries so changes are synced
>> -  ArmInvalidateTlb ();
>> -
>> +  if (FlushTlbs) {
>> +    ArmInvalidateTlb ();
>> +  }
>>    return Status;
>>  }
>>
>> --
>> 2.7.4
>>


  reply	other threads:[~2017-03-06 15:06 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-02 10:36 [PATCH v2 0/4] ArmPkg, ArmVirtpkg ARM: enable strict memory protection Ard Biesheuvel
2017-03-02 10:36 ` [PATCH v2 1/4] ArmPkg/CpuDxe ARM: avoid splitting page table sections unnecessarily Ard Biesheuvel
2017-03-06 14:12   ` Leif Lindholm
2017-03-06 14:55     ` Ard Biesheuvel
2017-03-06 16:24       ` Leif Lindholm
2017-03-02 10:36 ` [PATCH v2 2/4] ArmPkg/CpuDxe ARM: avoid unnecessary cache/TLB maintenance Ard Biesheuvel
2017-03-06 14:27   ` Leif Lindholm
2017-03-06 15:06     ` Ard Biesheuvel [this message]
2017-03-02 10:36 ` [PATCH v2 3/4] ArmPkg/CpuDxe ARM: honour RO/XP attributes in SetMemoryAttributes() Ard Biesheuvel
2017-03-06 14:48   ` Leif Lindholm
2017-03-06 15:11     ` Ard Biesheuvel
2017-03-06 16:40       ` Leif Lindholm
2017-03-02 10:36 ` [PATCH v2 4/4] ArmVirtPkg: enable PE/COFF image and memory protection for ARM platforms Ard Biesheuvel

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='CAKv+Gu_Cy4fUiRhf0vtFihb33dLvWsWqV3VOZZMCsw2Jn=h_nA@mail.gmail.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