From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 1C25520945BE6 for ; Wed, 13 Sep 2017 10:25:14 -0700 (PDT) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 13 Sep 2017 10:28:11 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.42,389,1500966000"; d="scan'208";a="1014095465" Received: from cwbutler-mobl.amr.corp.intel.com (HELO localhost) ([10.254.13.190]) by orsmga003.jf.intel.com with ESMTP; 13 Sep 2017 10:28:10 -0700 MIME-Version: 1.0 To: "Wang, Jian J" , edk2-devel@lists.01.org Message-ID: <150532368984.21662.15999032054940467421@jljusten-skl> From: Jordan Justen In-Reply-To: <20170913092507.12504-2-jian.j.wang@intel.com> Cc: Jiewen Yao , Eric Dong , Star Zeng , Laszlo Ersek , "Kinney, Michael D" , "Wolman, Ayellet" References: <20170913092507.12504-1-jian.j.wang@intel.com> <20170913092507.12504-2-jian.j.wang@intel.com> User-Agent: alot/0.6 Date: Wed, 13 Sep 2017 10:28:10 -0700 Subject: Re: [PATCH 1/4] MdeModulePkg/Core: Implement NULL pointer detection in EDK-II Core. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Sep 2017 17:25:14 -0000 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable On 2017-09-13 02:25:04, Wang, Jian J wrote: > The mechanism behind is to trigger a page fault exception at address 0. T= his can be made by disabling page 0 (0-4095) during page table setup. So th= is feature can only be available on platform with paging enabled. Once this= feature is enabled, any code, like CSM, which has to access memory in page= 0 needs to enable this page temporarily in advance and disable it afterwar= ds. PcdNullPointerDetectionPropertyMask is used to control and elaborate th= e use cases. > Your commit message line is > 450 columns. https://github.com/tianocore/tianocore.github.io/wiki/Commit-Message-Format I think BaseTools/Scripts/PatchCheck.py can help detect this issue. (more below...) > Cc: Jiewen Yao > Cc: Eric Dong > Cc: Star Zeng > Cc: Laszlo Ersek > Cc: Justen, Jordan L > Cc: Kinney, Michael D > Cc: Wolman, Ayellet > Suggested-by: Wolman, Ayellet > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Wang, Jian J > --- > MdeModulePkg/Core/Dxe/DxeMain.inf | 3 +- > MdeModulePkg/Core/Dxe/Mem/Page.c | 21 ++++++---- > MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c | 47 ++++++++++++++++++= +++ > MdeModulePkg/Core/DxeIplPeim/DxeIpl.h | 15 +++++++ > MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 3 +- > MdeModulePkg/Core/DxeIplPeim/DxeLoad.c | 53 ++++++++++++++++++= ++++++ > MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c | 8 +++- > MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c | 2 + > MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 23 ++++++---- > MdeModulePkg/MdeModulePkg.dec | 12 ++++++ > 10 files changed, 167 insertions(+), 20 deletions(-) > = > diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/Dx= eMain.inf > index 30d5984f7c..273b8b7c0e 100644 > --- a/MdeModulePkg/Core/Dxe/DxeMain.inf > +++ b/MdeModulePkg/Core/Dxe/DxeMain.inf > @@ -179,7 +179,7 @@ > gEfiWatchdogTimerArchProtocolGuid ## CONSUMES > = > [FeaturePcd] > - gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport = ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport = ## CONSUMES Why is this line changed? > = > [Pcd] > gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber= ## SOMETIMES_CONSUMES > @@ -192,6 +192,7 @@ > gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable = ## CONSUMES > gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy = ## CONSUMES > gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy = ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask = ## CONSUMES > = > # [Hob] > # RESOURCE_DESCRIPTOR ## CONSUMES > diff --git a/MdeModulePkg/Core/Dxe/Mem/Page.c b/MdeModulePkg/Core/Dxe/Mem= /Page.c > index a142c79ee2..2e0b72f864 100644 > --- a/MdeModulePkg/Core/Dxe/Mem/Page.c > +++ b/MdeModulePkg/Core/Dxe/Mem/Page.c > @@ -170,6 +170,7 @@ CoreAddRange ( > { > LIST_ENTRY *Link; > MEMORY_MAP *Entry; > + EFI_STATUS Status; > = > ASSERT ((Start & EFI_PAGE_MASK) =3D=3D 0); > ASSERT (End > Start) ; > @@ -188,7 +189,17 @@ CoreAddRange ( > // used for other purposes. > // = > if (Type =3D=3D EfiConventionalMemory && Start =3D=3D 0 && (End >=3D E= FI_PAGE_SIZE - 1)) { > - SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0); > + if ((PcdGet8(PcdNullPointerDetectionPropertyMask) & BIT0) =3D=3D 0) { > + SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0); > + } else if (gCpu !=3D NULL) { > + Status =3D gCpu->SetMemoryAttributes(gCpu, 0, EFI_PAGE_SIZE, 0); > + ASSERT_EFI_ERROR(Status); > + > + SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0); > + > + Status =3D gCpu->SetMemoryAttributes(gCpu, 0, EFI_PAGE_SIZE, EFI_M= EMORY_RP); > + ASSERT_EFI_ERROR(Status); > + } > } > = > // > @@ -1972,11 +1983,3 @@ Done: > return Status; > } > = > - > - > - > - > - > - > - > - > diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/MdeModulePkg= /Core/Dxe/Misc/MemoryProtection.c > index a73c4ccd64..2367d674e1 100644 > --- a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c > +++ b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c > @@ -995,6 +995,36 @@ MemoryProtectionExitBootServicesCallback ( > } > } > = > +/** > + Disable NULL pointer detection after EndOfDxe. This is a workaround re= sort in = > + order to skip unfixable NULL pointer access issues detected in OptionR= OM or = > + boot loaders. > + > + @param[in] Event The Event this notify function registered to. > + @param[in] Context Pointer to the context data registered to the Ev= ent. > +**/ > +VOID > +EFIAPI > +DisableNullDetectionAtTheEndOfDxe ( > + EFI_EVENT Event, > + VOID *Context > + ) > +{ > + EFI_STATUS Status; > + > + DEBUG((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n")); > + // > + // Disable NULL pointer detection by enabling first 4K page > + // > + Status =3D gCpu->SetMemoryAttributes(gCpu, 0, EFI_PAGE_SIZE, 0); > + ASSERT_EFI_ERROR(Status); > + > + CoreCloseEvent (Event); > + DEBUG((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n")); > + > + return; > +} > + > /** > Initialize Memory Protection support. > **/ > @@ -1006,6 +1036,7 @@ CoreInitializeMemoryProtection ( > { > EFI_STATUS Status; > EFI_EVENT Event; > + EFI_EVENT EndOfDxeEvent; > VOID *Registration; > = > mImageProtectionPolicy =3D PcdGet32(PcdImageProtectionPolicy); > @@ -1044,6 +1075,22 @@ CoreInitializeMemoryProtection ( > ); > ASSERT_EFI_ERROR(Status); > } > + > + // > + // Register a callback to disable NULL pointer detection at EndOfDxe > + // > + if ((PcdGet8(PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7)) =3D= =3D (BIT0|BIT7)) { > + Status =3D CoreCreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + DisableNullDetectionAtTheEndOfDxe, > + NULL, > + &gEfiEndOfDxeEventGroupGuid, > + &EndOfDxeEvent > + ); > + ASSERT_EFI_ERROR (Status); > + } > + > return ; > } > = > diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.h b/MdeModulePkg/Core/Dx= eIplPeim/DxeIpl.h > index 72d2532f50..104599156c 100644 > --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.h > +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.h > @@ -52,6 +52,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITH= ER EXPRESS OR IMPLIED. > #define STACK_SIZE 0x20000 > #define BSP_STORE_SIZE 0x4000 > = > +#define NULL_DETECTION_ENABLED ((PcdGet8(PcdNullPointerDetectionPropert= yMask) & BIT0) !=3D 0) I think maybe the code style would look better if you defined a function for this rather than using a macro. What do you think? > = > // > // This PPI is installed to indicate the end of the PEI usage of memory > @@ -240,4 +241,18 @@ Decompress ( > OUT UINTN *OutputSize > ); > = > +/** > + Clear legacy memory located at the first 4K-page. > + > + This function traverses the whole HOB list to check if memory from 0 = to 4095 = > + exists and has not been allocated, and then clear it if so. > + > + @param HoStart The start of HobList passed to DxeCore. > + > +**/ > +VOID > +ClearLegacyMemory( > + IN VOID *HobStart > + ); > + > #endif > diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/= DxeIplPeim/DxeIpl.inf > index c54afe4aa6..fde70f94bb 100644 > --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf > +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf > @@ -110,11 +110,12 @@ > gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplBuildPageTables ## CONSU= MES > = > [FeaturePcd] > - gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress ## CONSU= MES > + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress = ## CONSUMES > = > [Pcd.IA32,Pcd.X64] > gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable = ## SOMETIMES_CONSUMES > gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask = ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask = ## CONSUMES > = > [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64] > gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMET= IMES_CONSUMES > diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c b/MdeModulePkg/Core/D= xeIplPeim/DxeLoad.c > index 50b5440d15..b5f9d92f5b 100644 > --- a/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c > +++ b/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c > @@ -825,3 +825,56 @@ UpdateStackHob ( > Hob.Raw =3D GET_NEXT_HOB (Hob); > } > } > + > +/** > + Clear legacy memory located at the first 4K-page, if available. > + > + This function traverses the whole HOB list to check if memory from 0 = to 4095 = > + exists and has not been allocated, and then clear it if so. > + > + @param HoStart The start of HobList passed to DxeCo= re. > + > +**/ > +VOID > +ClearLegacyMemory( > + IN VOID *HobStart > + ) > +{ > + EFI_PEI_HOB_POINTERS RscDescHob; > + EFI_PEI_HOB_POINTERS MemAllocHob; > + BOOLEAN DoClear; > + > + RscDescHob.Raw =3D HobStart; > + MemAllocHob.Raw =3D HobStart; > + DoClear =3D FALSE; > + > + // > + // Check if page 0 exists and free > + // > + while ((RscDescHob.Raw =3D GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTO= R, RscDescHob.Raw)) !=3D NULL) { This code line is longer than 80 columns. There are more cases of this in your patchset. -Jordan > + if (RscDescHob.ResourceDescriptor->ResourceType =3D=3D EFI_RESOURCE_= SYSTEM_MEMORY && = > + RscDescHob.ResourceDescriptor->PhysicalStart =3D=3D 0) { > + DoClear =3D TRUE; > + // = > + // Make sure memory at 0-4095 has not been allocated. > + // > + while ((MemAllocHob.Raw =3D GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCA= TION, MemAllocHob.Raw)) !=3D NULL) { > + if (MemAllocHob.MemoryAllocation->AllocDescriptor.MemoryBaseAddr= ess < EFI_PAGE_SIZE) { > + DoClear =3D FALSE; > + break; > + } > + MemAllocHob.Raw =3D GET_NEXT_HOB (MemAllocHob); > + } > + break; > + } > + RscDescHob.Raw =3D GET_NEXT_HOB (RscDescHob); > + } > + > + if (DoClear) { > + DEBUG((DEBUG_INFO, "Clearing first 4K-page!\r\n")); > + SetMem(NULL, EFI_PAGE_SIZE, 0); > + } > + > + return; > +} > + > diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModuleP= kg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c > index 1957326caf..a8aa0d5d1b 100644 > --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c > +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c > @@ -123,7 +123,8 @@ Create4GPageTablesIa32Pae ( > PageDirectoryPointerEntry->Bits.Present =3D 1; > = > for (IndexOfPageDirectoryEntries =3D 0; IndexOfPageDirectoryEntries = < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress= +=3D SIZE_2MB) { > - if ((PhysicalAddress < StackBase + StackSize) && ((PhysicalAddress= + SIZE_2MB) > StackBase)) { > + if ((NULL_DETECTION_ENABLED && PhysicalAddress =3D=3D 0) > + || ((PhysicalAddress < StackBase + StackSize) && ((PhysicalAdd= ress + SIZE_2MB) > StackBase))) { > // > // Need to split this 2M page that covers stack range. > // > @@ -240,6 +241,8 @@ HandOffToDxeCore ( > EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi; > BOOLEAN BuildPageTablesIa32Pae; > = > + ClearLegacyMemory(HobList.Raw); > + > Status =3D PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_= PAGES (STACK_SIZE), &BaseOfStack); > ASSERT_EFI_ERROR (Status); > = > @@ -379,7 +382,8 @@ HandOffToDxeCore ( > TopOfStack =3D (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfSt= ack, CPU_STACK_ALIGNMENT); > = > PageTables =3D 0; > - BuildPageTablesIa32Pae =3D (BOOLEAN) (PcdGetBool (PcdSetNxForStack) = && IsIa32PaeSupport () && IsExecuteDisableBitAvailable ()); > + BuildPageTablesIa32Pae =3D (BOOLEAN) (IsIa32PaeSupport () && IsExecu= teDisableBitAvailable () > + && (PcdGetBool (PcdSetNxForStack= ) || NULL_DETECTION_ENABLED)); > if (BuildPageTablesIa32Pae) { > PageTables =3D Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE); > EnableExecuteDisableBit (); > diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c b/MdeModulePk= g/Core/DxeIplPeim/X64/DxeLoadFunc.c > index 6488880eab..50a8d77a5b 100644 > --- a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c > +++ b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c > @@ -42,6 +42,8 @@ HandOffToDxeCore ( > EFI_VECTOR_HANDOFF_INFO *VectorInfo; > EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi; > = > + ClearLegacyMemory(HobList.Raw); > + > // > // Get Vector Hand-off Info PPI and build Guided HOB > // > diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModule= Pkg/Core/DxeIplPeim/X64/VirtualMemory.c > index 48150be4e1..ccd6e10cb2 100644 > --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c > +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c > @@ -90,8 +90,14 @@ Split2MPageTo4K ( > // > PageTableEntry->Uint64 =3D (UINT64) PhysicalAddress4K | AddressEncMa= sk; > PageTableEntry->Bits.ReadWrite =3D 1; > - PageTableEntry->Bits.Present =3D 1; > - if ((PhysicalAddress4K >=3D StackBase) && (PhysicalAddress4K < Stack= Base + StackSize)) { > + > + if (NULL_DETECTION_ENABLED && PhysicalAddress4K =3D=3D 0) { > + PageTableEntry->Bits.Present =3D 0; > + } else { > + PageTableEntry->Bits.Present =3D 1; > + } > + > + if (PcdGetBool (PcdSetNxForStack) && (PhysicalAddress4K >=3D StackBa= se) && (PhysicalAddress4K < StackBase + StackSize)) { > // > // Set Nx bit for stack. > // > @@ -137,9 +143,10 @@ Split1GPageTo2M ( > = > PhysicalAddress2M =3D PhysicalAddress; > for (IndexOfPageDirectoryEntries =3D 0; IndexOfPageDirectoryEntries < = 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M= +=3D SIZE_2MB) { > - if ((PhysicalAddress2M < StackBase + StackSize) && ((PhysicalAddress= 2M + SIZE_2MB) > StackBase)) { > + if ((NULL_DETECTION_ENABLED && PhysicalAddress2M =3D=3D 0) > + || (PcdGetBool (PcdSetNxForStack) && (PhysicalAddress2M < StackB= ase + StackSize) && ((PhysicalAddress2M + SIZE_2MB) > StackBase))) { > // > - // Need to split this 2M page that covers stack range. > + // Need to split this 2M page that covers NULL or stack range. > // > Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry,= StackBase, StackSize); > } else { > @@ -279,7 +286,8 @@ CreateIdentityMappingPageTables ( > PageDirectory1GEntry =3D (VOID *) PageDirectoryPointerEntry; > = > for (IndexOfPageDirectoryEntries =3D 0; IndexOfPageDirectoryEntrie= s < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress= +=3D SIZE_1GB) { > - if (PcdGetBool (PcdSetNxForStack) && (PageAddress < StackBase + = StackSize) && ((PageAddress + SIZE_1GB) > StackBase)) { > + if ((NULL_DETECTION_ENABLED && PageAddress =3D=3D 0) > + || (PcdGetBool (PcdSetNxForStack) && (PageAddress < StackBas= e + StackSize) && ((PageAddress + SIZE_1GB) > StackBase))) { > Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry,= StackBase, StackSize); > } else { > // > @@ -308,9 +316,10 @@ CreateIdentityMappingPageTables ( > PageDirectoryPointerEntry->Bits.Present =3D 1; > = > for (IndexOfPageDirectoryEntries =3D 0; IndexOfPageDirectoryEntr= ies < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress= +=3D SIZE_2MB) { > - if (PcdGetBool (PcdSetNxForStack) && (PageAddress < StackBase = + StackSize) && ((PageAddress + SIZE_2MB) > StackBase)) { > + if ((NULL_DETECTION_ENABLED && PageAddress =3D=3D 0) > + || (PcdGetBool (PcdSetNxForStack) && (PageAddress < StackB= ase + StackSize) && ((PageAddress + SIZE_2MB) > StackBase))) { > // > - // Need to split this 2M page that covers stack range. > + // Need to split this 2M page that covers NULL or stack rang= e. > // > Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry,= StackBase, StackSize); > } else { > diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec > index 593bff357a..1cc84894af 100644 > --- a/MdeModulePkg/MdeModulePkg.dec > +++ b/MdeModulePkg/MdeModulePkg.dec > @@ -860,6 +860,18 @@ > # @ValidList 0x80000006 | 0x03058002 > gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable|0x03058002|UINT= 32|0x30001040 > = > + ## Mask to control the NULL address detection in code for different ph= ases. > + # If enabled, accessing NULL address in UEFI or SMM code can be caugh= t.

> + # BIT0 - Enable NULL pointer detection for UEFI.
> + # BIT1 - Enable NULL pointer detection for SMM.
> + # BIT2..6 - Reserved for future uses.
> + # BIT7 - Disable NULL pointer detection just after EndOfDxe.
> + # This is a workaround for those unsolvable NULL access i= ssues in OptionROM, boot loader, etc. > + # It can also help to avoid unnecessary exception caused = by legacy memory (0-4095) access after = > + # EndOfDxe, such as Windows 7 boot on Qemu.
> + # @Prompt Enable NULL address detection. > + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask|0x0= |UINT8|0x30001050 > + > [PcdsFixedAtBuild, PcdsPatchableInModule] > ## Dynamic type PCD can be registered callback function for Pcd settin= g action. > # PcdMaxPeiPcdCallBackNumberPerPcdEntry indicates the maximum number = of callback function > -- = > 2.14.1.windows.1 >=20