On 03/21/13 00:38, Kinney, Michael D wrote:
> Please see the attached patch that guarantees that free memory in the 4K
> page starting at address 0 is always cleared to 0.  The algorithm is to
> clear page zero if it is registered with the DXE Core with type
> EfiConventionalMemory, and to also clear page zero if it is freed using
> the UEFI Boot Service FreePages().  The unit test for this patch exposed
> a bug in the DXE Core that generated an ASSERT() when the page at
> address zero is freed and DEBUG_CLEAR_MEMORY() macros are enabled.  If
> DEBUG_CLEAR_MEMORY() is enabled and the page at address 0 is freed, then
> DEBUG_CLEAR_MEMORY() is invoked skipping over the first 4K page.
>
>
>
> This patch improves OS compatibility for OSes that may evaluate page 0
> for legacy data structures.  Before this patch, free memory may contain
> random values which induces random boot failures for some OSes.  This
> patch may also help find NULL pointer bugs sooner because all of the
> fields in a data structure dereferenced through NULL will also be NULL now.

I'm including the patch here for review:

> Index: Dxe/Mem/Page.c
> ===================================================================
> --- Dxe/Mem/Page.c    (revision 14133)
> +++ Dxe/Mem/Page.c    (working copy)
> @@ -1,7 +1,7 @@
>  /** @file
>    UEFI Memory page management functions.
>
> -Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
>  This program and the accompanying materials
>  are licensed and made available under the terms and conditions of the BSD 
> License
>  which accompanies this distribution.  The full text of the license may be 
> found at
> @@ -177,8 +177,21 @@
>    ASSERT_LOCKED (&gMemoryLock);
>
>    DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
> -
> +
>    //
> +  // If memory of type EfiConventionalMemory is being added that includes 
> the page
> +  // starting at address 0, then zero the page starting at address 0.  This 
> has
> +  // two benifits.  It helps find NULL pointer bugs and it also maximizes
> +  // compatibility with operating systems that may evaluate memory in this 
> page
> +  // for legacy data structures.  If memory of any other type is added 
> starting
> +  // at address 0, then do not zero the page at address 0 because the page 
> is being
> +  // used for other purposes.
> +  //
> +  if (Type == EfiConventionalMemory && Start == 0 && (End >= EFI_PAGE_SIZE - 
> 1)) {
> +    SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);
> +  }
> +
> +  //
>    // Memory map being altered so updated key
>    //
>    mMemoryMapKey += 1;

This hunk (for function CoreAddRange()) seems OK. "End" is inclusive,
hence we're checking whether the range being added covers the zero page
entirely.


> @@ -834,7 +847,18 @@
>      //
>      CoreAddRange (NewType, Start, RangeEnd, Attribute);
>      if (NewType == EfiConventionalMemory) {
> -      DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 
> 1));
> +      //
> +      // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
> +      // macro will ASSERT() if address is 0.  Instead, CoreAddRange() 
> guarantees
> +      // that the page starting at address 0 is always filled with zeros.
> +      //
> +      if (Start == 0) {
> +        if (RangeEnd > EFI_PAGE_SIZE) {
> +          DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) 
> (RangeEnd - EFI_PAGE_SIZE + 1));
> +        }
> +      } else {
> +        DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start 
> + 1));
> +      }
>      }
>
>      //

This hunk (for CoreConvertPages()) immediately follows a call to
CoreAddRange(). The interface contract of CoreAddRange() requires
[Start, RangeEnd] (inclusive) to cover at least one page, and RangeEnd
to be the last (zero-based) offset within a page.

The (Start > 0) branch is clearly OK.

The (RangeEnd > EFI_PAGE_SIZE) controlling expression is off by one "in
theory". "RangeEnd" is inclusive, hence we should put the "touches
another page" condition as (RangeEnd >= EFI_PAGE_SIZE) instead.

The difference would only matter for (RangeEnd == EFI_PAGE_SIZE), in
which case the additional range length (RangeEnd - EFI_PAGE_SIZE + 1)
would evaluate to 1 precisely. However this case is impossible due to
the CoreAddRange() interface contract:
- end of page #0:                 EFI_PAGE_SIZE - 1 < EFI_PAGE_SIZE
- end of page #1: EFI_PAGE_SIZE + EFI_PAGE_SIZE - 1 > EFI_PAGE_SIZE

Reviewed-by: Laszlo Ersek <ler...@redhat.com>

------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_mar
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to