From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.20; helo=mga02.intel.com; envelope-from=eric.dong@intel.com; receiver=edk2-devel@lists.01.org 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 AF6FF211211E3 for ; Wed, 5 Sep 2018 18:46:06 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 05 Sep 2018 18:46:05 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,334,1531810800"; d="scan'208";a="70703712" Received: from fmsmsx107.amr.corp.intel.com ([10.18.124.205]) by orsmga007.jf.intel.com with ESMTP; 05 Sep 2018 18:45:57 -0700 Received: from FMSMSX110.amr.corp.intel.com (10.18.116.10) by fmsmsx107.amr.corp.intel.com (10.18.124.205) with Microsoft SMTP Server (TLS) id 14.3.319.2; Wed, 5 Sep 2018 18:45:57 -0700 Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by fmsmsx110.amr.corp.intel.com (10.18.116.10) with Microsoft SMTP Server (TLS) id 14.3.319.2; Wed, 5 Sep 2018 18:45:56 -0700 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.226]) by SHSMSX151.ccr.corp.intel.com ([169.254.3.16]) with mapi id 14.03.0319.002; Thu, 6 Sep 2018 09:45:55 +0800 From: "Dong, Eric" To: "Wang, Jian J" , "edk2-devel@lists.01.org" CC: Laszlo Ersek , "Ni, Ruiyu" , "Yao, Jiewen" , "Zeng, Star" , "Ware, Ryan R" Thread-Topic: [PATCH 4/4] UefiCpuPkg/CpuMpPei: support stack guard feature Thread-Index: AQHUQzSAouI57NyqMEqzAIGgghbcVqTif7Wg Date: Thu, 6 Sep 2018 01:45:55 +0000 Message-ID: References: <20180903031550.4440-1-jian.j.wang@intel.com> <20180903031550.4440-5-jian.j.wang@intel.com> In-Reply-To: <20180903031550.4440-5-jian.j.wang@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH 4/4] UefiCpuPkg/CpuMpPei: support stack guard feature X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 06 Sep 2018 01:46:07 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi Jian, Below code has ECC issue, please check with ECC tool to fix all ECC issues. /** Initializes MP and exceptions handlers. @retval EFI_SUCCESS MP was successfully initialized. @retval others Error occurred in MP initialization. **/ EFI_STATUS InitializeCpuMpWorker ( IN CONST EFI_PEI_SERVICES **PeiServices ) With ECC issues fixed, Reviewed-by: Eric Dong Thanks, Eric > -----Original Message----- > From: Wang, Jian J > Sent: Monday, September 3, 2018 11:16 AM > To: edk2-devel@lists.01.org > Cc: Dong, Eric ; Laszlo Ersek ; N= i, > Ruiyu ; Yao, Jiewen ; Zeng, > Star ; Ware, Ryan R > Subject: [PATCH 4/4] UefiCpuPkg/CpuMpPei: support stack guard feature >=20 > This feature is the same as Stack Guard enabled in driver CpuDxe but appl= ies > to PEI phase. Due to the specialty in PEI module dispatching, this driver= is > changed to do the actual initialization in notify callback of event > gEfiPeiMemoryDiscoveredPpiGuid. This can let the stack guard apply to as > most PEI drivers as possible. >=20 > To let Stack Guard work, some simple page table management code are > introduced to setup Guard page at base of stack for each processor. >=20 > Cc: Eric Dong > Cc: Laszlo Ersek > Cc: Ruiyu Ni > Cc: Jiewen Yao > Cc: Star Zeng > Cc: "Ware, Ryan R" > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Jian J Wang > --- > UefiCpuPkg/CpuMpPei/CpuMpPei.c | 269 ++++++++++++++++- > UefiCpuPkg/CpuMpPei/CpuMpPei.h | 14 + > UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 11 +- > UefiCpuPkg/CpuMpPei/CpuPaging.c | 637 > +++++++++++++++++++++++++++++++++++++++ > 4 files changed, 916 insertions(+), 15 deletions(-) create mode 100644 > UefiCpuPkg/CpuMpPei/CpuPaging.c >=20 > diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c > b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index 7c94d5a6d7..e3762daf39 100644 > --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c > +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c > @@ -409,25 +409,225 @@ PeiWhoAmI ( > } >=20 > /** > - The Entry point of the MP CPU PEIM. > + Get GDT register value. >=20 > - This function will wakeup APs and collect CPU AP count and install the > - Mp Service Ppi. > + This function is mainly for AP purpose because AP may have different > + GDT table than BSP. >=20 > - @param FileHandle Handle of the file being invoked. > - @param PeiServices Describes the list of possible PEI Services. > + @param[in,out] Buffer The pointer to private data buffer. >=20 > - @retval EFI_SUCCESS MpServicePpi is installed successfully. > +**/ > +VOID > +EFIAPI > +GetGdtr ( > + IN OUT VOID *Buffer > + ) > +{ > + AsmReadGdtr ((IA32_DESCRIPTOR *)Buffer); } > + > +/** > + Initializes CPU exceptions handlers for the sake of stack switch > requirement. > + > + This function is a wrapper of InitializeCpuExceptionHandlersEx. It's > + mainly for the sake of AP's init because of EFI_AP_PROCEDURE API > requirement. > + > + @param[in,out] Buffer The pointer to private data buffer. >=20 > **/ > -EFI_STATUS > +VOID > EFIAPI > -CpuMpPeimInit ( > - IN EFI_PEI_FILE_HANDLE FileHandle, > +InitializeExceptionStackSwitchHandlers ( > + IN OUT VOID *Buffer > + ) > +{ > + CPU_EXCEPTION_INIT_DATA *EssData; > + IA32_DESCRIPTOR Idtr; > + EFI_STATUS Status; > + > + EssData =3D Buffer; > + // > + // We don't plan to replace IDT table with a new one, but we should > +not assume > + // the AP's IDT is the same as BSP's IDT either. > + // > + AsmReadIdtr (&Idtr); > + EssData->Ia32.IdtTable =3D (VOID *)Idtr.Base; > + EssData->Ia32.IdtTableSize =3D Idtr.Limit + 1; > + Status =3D InitializeCpuExceptionHandlersEx (NULL, EssData); > + ASSERT_EFI_ERROR (Status); > +} > + > +/** > + Initializes MP exceptions handlers for the sake of stack switch requir= ement. > + > + This function will allocate required resources required to setup > + stack switch and pass them through CPU_EXCEPTION_INIT_DATA to each > logic processor. > + > +**/ > +VOID > +InitializeMpExceptionStackSwitchHandlers ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + UINTN Index; > + UINTN Bsp; > + UINTN ExceptionNumber; > + UINTN OldGdtSize; > + UINTN NewGdtSize; > + UINTN NewStackSize; > + IA32_DESCRIPTOR Gdtr; > + CPU_EXCEPTION_INIT_DATA EssData; > + UINT8 *GdtBuffer; > + UINT8 *StackTop; > + UINTN NumberOfProcessors; > + > + if (!PcdGetBool (PcdCpuStackGuard)) { > + return; > + } > + > + MpInitLibGetNumberOfProcessors(&NumberOfProcessors, NULL); > + MpInitLibWhoAmI (&Bsp); > + > + ExceptionNumber =3D FixedPcdGetSize (PcdCpuStackSwitchExceptionList); > + NewStackSize =3D FixedPcdGet32 (PcdCpuKnownGoodStackSize) * > + ExceptionNumber; > + > + Status =3D PeiServicesAllocatePool ( > + NewStackSize * NumberOfProcessors, > + (VOID **)&StackTop > + ); > + ASSERT(StackTop !=3D NULL); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return; > + } > + StackTop +=3D NewStackSize * NumberOfProcessors; > + > + // > + // The default exception handlers must have been initialized. Let's > + just skip // it in this method. > + // > + EssData.Ia32.Revision =3D CPU_EXCEPTION_INIT_DATA_REV; > + EssData.Ia32.InitDefaultHandlers =3D FALSE; > + > + EssData.Ia32.StackSwitchExceptions =3D > + FixedPcdGetPtr(PcdCpuStackSwitchExceptionList); > + EssData.Ia32.StackSwitchExceptionNumber =3D ExceptionNumber; > + EssData.Ia32.KnownGoodStackSize =3D > + FixedPcdGet32(PcdCpuKnownGoodStackSize); > + > + // > + // Initialize Gdtr to suppress incorrect compiler/analyzer warnings. > + // > + Gdtr.Base =3D 0; > + Gdtr.Limit =3D 0; > + for (Index =3D 0; Index < NumberOfProcessors; ++Index) { > + // > + // To support stack switch, we need to re-construct GDT but not IDT. > + // > + if (Index =3D=3D Bsp) { > + GetGdtr(&Gdtr); > + } else { > + // > + // AP might have different size of GDT from BSP. > + // > + MpInitLibStartupThisAP (GetGdtr, Index, NULL, 0, (VOID *)&Gdtr, NU= LL); > + } > + > + // > + // X64 needs only one TSS of current task working for all exceptions > + // because of its IST feature. IA32 needs one TSS for each exception > + // in addition to current task. Since AP is not supposed to allocate > + // memory, we have to do it in BSP. To simplify the code, we allocat= e > + // memory for IA32 case to cover both IA32 and X64 exception stack > + // switch. > + // > + // Layout of memory to allocate for each processor: > + // -------------------------------- > + // | Alignment | (just in case) > + // -------------------------------- > + // | | > + // | Original GDT | > + // | | > + // -------------------------------- > + // | Current task descriptor | > + // -------------------------------- > + // | | > + // | Exception task descriptors | X ExceptionNumber > + // | | > + // -------------------------------- > + // | Current task-state segment | > + // -------------------------------- > + // | | > + // | Exception task-state segment | X ExceptionNumber > + // | | > + // -------------------------------- > + // > + OldGdtSize =3D Gdtr.Limit + 1; > + EssData.Ia32.ExceptionTssDescSize =3D sizeof (IA32_TSS_DESCRIPTOR) * > + (ExceptionNumber + 1); > + EssData.Ia32.ExceptionTssSize =3D sizeof (IA32_TASK_STATE_SEGMENT) * > + (ExceptionNumber + 1); > + NewGdtSize =3D sizeof (IA32_TSS_DESCRIPTOR) + > + OldGdtSize + > + EssData.Ia32.ExceptionTssDescSize + > + EssData.Ia32.ExceptionTssSize; > + > + Status =3D PeiServicesAllocatePool ( > + NewGdtSize, > + (VOID **)&GdtBuffer > + ); > + ASSERT (GdtBuffer !=3D NULL); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return; > + } > + > + // > + // Make sure GDT table alignment > + // > + EssData.Ia32.GdtTable =3D ALIGN_POINTER(GdtBuffer, sizeof > (IA32_TSS_DESCRIPTOR)); > + NewGdtSize -=3D ((UINT8 *)EssData.Ia32.GdtTable - GdtBuffer); > + EssData.Ia32.GdtTableSize =3D NewGdtSize; > + > + EssData.Ia32.ExceptionTssDesc =3D ((UINT8 *)EssData.Ia32.GdtTable + > OldGdtSize); > + EssData.Ia32.ExceptionTss =3D ((UINT8 *)EssData.Ia32.GdtTable + > OldGdtSize + > + EssData.Ia32.ExceptionTssDescSize); > + > + EssData.Ia32.KnownGoodStackTop =3D (UINTN)StackTop; > + DEBUG ((DEBUG_INFO, > + "Exception stack top[cpu%lu]: 0x%lX\n", > + (UINT64)(UINTN)Index, > + (UINT64)(UINTN)StackTop)); > + > + if (Index =3D=3D Bsp) { > + InitializeExceptionStackSwitchHandlers (&EssData); > + } else { > + MpInitLibStartupThisAP ( > + InitializeExceptionStackSwitchHandlers, > + Index, > + NULL, > + 0, > + (VOID *)&EssData, > + NULL > + ); > + } > + > + StackTop -=3D NewStackSize; > + } > +} > + > +/** > + Initializes MP and exceptions handlers. > + > + @retval EFI_SUCCESS MP was successfully initialized. > + @retval others Error occurred in MP initialization. > + > +**/ > +EFI_STATUS > +InitializeCpuMpWorker ( > IN CONST EFI_PEI_SERVICES **PeiServices > ) > { > - EFI_STATUS Status; > + EFI_STATUS Status; > EFI_VECTOR_HANDOFF_INFO *VectorInfo; > EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi; >=20 > @@ -444,14 +644,24 @@ CpuMpPeimInit ( > if (Status =3D=3D EFI_SUCCESS) { > VectorInfo =3D VectorHandoffInfoPpi->Info; > } > - Status =3D InitializeCpuExceptionHandlers (VectorInfo); > - ASSERT_EFI_ERROR (Status); >=20 > // > - // Wakeup APs to do initialization > + // Initialize default handlers > // > + Status =3D InitializeCpuExceptionHandlers (VectorInfo); if (EFI_ERROR > + (Status)) { > + return Status; > + } > + > Status =3D MpInitLibInitialize (); > - ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Special initialization for the sake of Stack Guard // > + InitializeMpExceptionStackSwitchHandlers (); >=20 > // > // Update and publish CPU BIST information @@ -466,3 +676,34 @@ > CpuMpPeimInit ( >=20 > return Status; > } > + > +/** > + The Entry point of the MP CPU PEIM. > + > + This function will wakeup APs and collect CPU AP count and install > + the Mp Service Ppi. > + > + @param FileHandle Handle of the file being invoked. > + @param PeiServices Describes the list of possible PEI Services. > + > + @retval EFI_SUCCESS MpServicePpi is installed successfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +CpuMpPeimInit ( > + IN EFI_PEI_FILE_HANDLE FileHandle, > + IN CONST EFI_PEI_SERVICES **PeiServices > + ) > +{ > + EFI_STATUS Status; > + > + // > + // For the sake of special initialization needing to be done right > + after // memory discovery. > + // > + Status =3D PeiServicesNotifyPpi (&mPostMemNotifyList[0]); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} > diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h > b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index aae56658ec..846f16db3a > 100644 > --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h > +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h > @@ -402,4 +402,18 @@ SecPlatformInformation2 ( > OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 > *PlatformInformationRecord2 > ); >=20 > +/** > + Initializes MP and exceptions handlers. > + > + @retval EFI_SUCCESS MP was successfully initialized. > + @retval others Error occurred in MP initialization. > + > +**/ > +EFI_STATUS > +InitializeCpuMpWorker ( > + IN CONST EFI_PEI_SERVICES **PeiServices > + ); > + > +extern EFI_PEI_NOTIFY_DESCRIPTOR mPostMemNotifyList[]; > + > #endif > diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf > b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf > index 3b40d88201..19cbf3345c 100644 > --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf > +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf > @@ -31,6 +31,7 @@ > CpuMpPei.h > CpuMpPei.c > CpuBist.c > + CpuPaging.c >=20 > [Packages] > MdePkg/MdePkg.dec > @@ -57,9 +58,17 @@ > ## UNDEFINED # HOB > gEfiSecPlatformInformation2PpiGuid > gEfiVectorHandoffInfoPpiGuid ## SOMETIMES_CONSUMES > + gEfiPeiMemoryDiscoveredPpiGuid > + > +[Pcd] > + > gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrM > ask ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard = ## > CONSUMES > + gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList > + gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize > + gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize >=20 > [Depex] > - gEfiPeiMemoryDiscoveredPpiGuid > + TRUE >=20 > [UserExtensions.TianoCore."ExtraFiles"] > CpuMpPeiExtra.uni > diff --git a/UefiCpuPkg/CpuMpPei/CpuPaging.c > b/UefiCpuPkg/CpuMpPei/CpuPaging.c new file mode 100644 index > 0000000000..5d18768e30 > --- /dev/null > +++ b/UefiCpuPkg/CpuMpPei/CpuPaging.c > @@ -0,0 +1,637 @@ > +/** @file > + Basic paging support for the CPU to enable Stack Guard. > + > +Copyright (c) 2018, Intel Corporation. All rights reserved.
> + > +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 http://opensource.org/licenses/bsd-license.php > + > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" > BASIS, > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER > EXPRESS OR IMPLIED. > + > +**/ > + > +#include > +#include > +#include #include > +#include > + > +#include "CpuMpPei.h" > + > +#define IA32_PG_P BIT0 > +#define IA32_PG_RW BIT1 > +#define IA32_PG_U BIT2 > +#define IA32_PG_A BIT5 > +#define IA32_PG_D BIT6 > +#define IA32_PG_PS BIT7 > +#define IA32_PG_NX BIT63 > + > +#define PAGE_ATTRIBUTE_BITS (IA32_PG_RW | IA32_PG_P) > +#define PAGE_PROGATE_BITS (IA32_PG_D | IA32_PG_A | IA32_PG_NX | > IA32_PG_U |\ > + PAGE_ATTRIBUTE_BITS) > + > +#define PAGING_PAE_INDEX_MASK 0x1FF > +#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull > +#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull > +#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull > +#define PAGING_512G_ADDRESS_MASK_64 0x000FFF8000000000ull > + > +typedef enum { > + PageNone =3D 0, > + PageMin =3D 1, > + Page4K =3D PageMin, > + Page2M =3D 2, > + Page1G =3D 3, > + Page512G =3D 4, > + PageMax =3D Page512G > +} PAGE_ATTRIBUTE; > + > +typedef struct { > + PAGE_ATTRIBUTE Attribute; > + UINT64 Length; > + UINT64 AddressMask; > + UINTN AddressBitOffset; > + UINTN AddressBitLength; > +} PAGE_ATTRIBUTE_TABLE; > + > +PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] =3D { > + {PageNone, 0, 0, 0, 0}, > + {Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64, 12, 9}, > + {Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64, 21, 9}, > + {Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64, 30, 9}, > + {Page512G, SIZE_512GB, PAGING_512G_ADDRESS_MASK_64, 39, 9}, }; > + > +EFI_STATUS > +EFIAPI > +MemoryDiscoveredPpiNotifyCallback ( > + IN EFI_PEI_SERVICES **PeiServices, > + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, > + IN VOID *Ppi > + ); > + > +EFI_PEI_NOTIFY_DESCRIPTOR mPostMemNotifyList[] =3D { > + { > + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | > EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), > + &gEfiPeiMemoryDiscoveredPpiGuid, > + MemoryDiscoveredPpiNotifyCallback > + } > +}; > + > +/** > + The function will check if IA32 PAE is supported. > + > + @retval TRUE IA32 PAE is supported. > + @retval FALSE IA32 PAE is not supported. > + > +**/ > +BOOLEAN > +IsIa32PaeSupported ( > + VOID > + ) > +{ > + UINT32 RegEax; > + CPUID_VERSION_INFO_EDX RegEdx; > + > + AsmCpuid (CPUID_SIGNATURE, &RegEax, NULL, NULL, NULL); if > (RegEax >=3D > + CPUID_VERSION_INFO) { > + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx.Uint32); > + if (RegEdx.Bits.PAE !=3D 0) { > + return TRUE; > + } > + } > + > + return FALSE; > +} > + > +/** > + This API provides a way to allocate memory for page table. > + > + @param Pages The number of 4 KB pages to allocate. > + > + @return A pointer to the allocated buffer or NULL if allocation fails. > + > +**/ > +VOID * > +AllocatePageTableMemory ( > + IN UINTN Pages > + ) > +{ > + VOID *Address; > + > + Address =3D AllocatePages(Pages); > + if (Address !=3D NULL) { > + ZeroMem(Address, EFI_PAGES_TO_SIZE (Pages)); } > + > + return Address; > +} > + > +/** > + Get the address width supported by current processor. > + > + @retval 32 If processor is in 32-bit mode. > + @retval 36-48 If processor is in 64-bit mode. > + > +**/ > +UINTN > +GetPhysicalAddressWidth ( > + VOID > + ) > +{ > + UINT32 RegEax; > + > + if (sizeof(UINTN) =3D=3D 4) { > + return 32; > + } > + > + AsmCpuid(CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); if > + (RegEax >=3D CPUID_VIR_PHY_ADDRESS_SIZE) { > + AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &RegEax, NULL, NULL, NULL); > + RegEax &=3D 0xFF; > + if (RegEax > 48) { > + return 48; > + } > + > + return (UINTN)RegEax; > + } > + > + return 36; > +} > + > +/** > + Get the type of top level page table. > + > + @retval Page512G PML4 paging. > + @retval Page1G PAE paing. > + > +**/ > +PAGE_ATTRIBUTE > +GetPageTableTopLevelType ( > + VOID > + ) > +{ > + MSR_IA32_EFER_REGISTER MsrEfer; > + > + MsrEfer.Uint64 =3D AsmReadMsr64 (MSR_CORE_IA32_EFER); > + > + return (MsrEfer.Bits.LMA =3D=3D 1) ? Page512G : Page1G; } > + > +/** > + Return page table entry matching the address. > + > + @param[in] Address The address to be checked. > + @param[out] PageAttributes The page attribute of the page entry. > + > + @return The page entry. > +**/ > +VOID * > +GetPageTableEntry ( > + IN PHYSICAL_ADDRESS Address, > + OUT PAGE_ATTRIBUTE *PageAttribute > + ) > +{ > + INTN Level; > + UINTN Index; > + UINT64 *PageTable; > + UINT64 AddressEncMask; > + > + AddressEncMask =3D PcdGet64 (PcdPteMemoryEncryptionAddressOrMask); > + PageTable =3D (UINT64 *)(UINTN)(AsmReadCr3 () & > + PAGING_4K_ADDRESS_MASK_64); for (Level =3D > (INTN)GetPageTableTopLevelType (); Level > 0; --Level) { > + Index =3D (UINTN)RShiftU64 (Address, > mPageAttributeTable[Level].AddressBitOffset); > + Index &=3D PAGING_PAE_INDEX_MASK; > + > + // > + // No mapping? > + // > + if (PageTable[Index] =3D=3D 0) { > + *PageAttribute =3D PageNone; > + return NULL; > + } > + > + // > + // Page memory? > + // > + if ((PageTable[Index] & IA32_PG_PS) !=3D 0 || Level =3D=3D PageMin) = { > + *PageAttribute =3D (PAGE_ATTRIBUTE)Level; > + return &PageTable[Index]; > + } > + > + // > + // Page directory or table > + // > + PageTable =3D (UINT64 *)(UINTN)(PageTable[Index] & > + ~AddressEncMask & > + PAGING_4K_ADDRESS_MASK_64); } > + > + *PageAttribute =3D PageNone; > + return NULL; > +} > + > +/** > + This function splits one page entry to smaller page entries. > + > + @param[in] PageEntry The page entry to be splitted. > + @param[in] PageAttribute The page attribute of the page entry. > + @param[in] SplitAttribute How to split the page entry. > + @param[in] Recursively Do the split recursively or not. > + > + @retval RETURN_SUCCESS The page entry is splitted. > + @retval RETURN_INVALID_PARAMETER If target page attribute is invalid > + @retval RETURN_OUT_OF_RESOURCES No resource to split page entry. > +**/ > +RETURN_STATUS > +SplitPage ( > + IN UINT64 *PageEntry, > + IN PAGE_ATTRIBUTE PageAttribute, > + IN PAGE_ATTRIBUTE SplitAttribute, > + IN BOOLEAN Recursively > + ) > +{ > + UINT64 BaseAddress; > + UINT64 *NewPageEntry; > + UINTN Index; > + UINT64 AddressEncMask; > + PAGE_ATTRIBUTE SplitTo; > + > + if (SplitAttribute =3D=3D PageNone || SplitAttribute >=3D PageAttribut= e) { > + ASSERT (SplitAttribute !=3D PageNone); > + ASSERT (SplitAttribute < PageAttribute); > + return RETURN_INVALID_PARAMETER; > + } > + > + NewPageEntry =3D AllocatePageTableMemory (1); if (NewPageEntry =3D=3D > + NULL) { > + ASSERT (NewPageEntry !=3D NULL); > + return RETURN_OUT_OF_RESOURCES; > + } > + > + // > + // One level down each step to achieve more compact page table. > + // > + SplitTo =3D PageAttribute - 1; > + AddressEncMask =3D PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) > & > + mPageAttributeTable[SplitTo].AddressMask; > + BaseAddress =3D *PageEntry & > + ~PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & > + mPageAttributeTable[PageAttribute].AddressMask; > + for (Index =3D 0; Index < SIZE_4KB / sizeof(UINT64); Index++) { > + NewPageEntry[Index] =3D BaseAddress | AddressEncMask | > + ((*PageEntry) & PAGE_PROGATE_BITS); > + > + if (SplitTo !=3D PageMin) { > + NewPageEntry[Index] |=3D IA32_PG_PS; > + } > + > + if (Recursively && SplitTo > SplitAttribute) { > + SplitPage (&NewPageEntry[Index], SplitTo, SplitAttribute, Recursiv= ely); > + } > + > + BaseAddress +=3D mPageAttributeTable[SplitTo].Length; > + } > + > + (*PageEntry) =3D (UINT64)(UINTN)NewPageEntry | AddressEncMask | > + PAGE_ATTRIBUTE_BITS; > + > + return RETURN_SUCCESS; > +} > + > +/** > + This function modifies the page attributes for the memory region > +specified > + by BaseAddress and Length from their current attributes to the > +attributes > + specified by Attributes. > + > + Caller should make sure BaseAddress and Length is at page boundary. > + > + @param[in] BaseAddress Start address of a memory region. > + @param[in] Length Size in bytes of the memory region. > + @param[in] Attributes Bit mask of attributes to modify. > + > + @retval RETURN_SUCCESS The attributes were modified for the > memory > + region. > + @retval RETURN_INVALID_PARAMETER Length is zero; or, > + Attributes specified an illegal comb= ination > + of attributes that cannot be set tog= ether; or > + Addressis not 4KB aligned. > + @retval RETURN_OUT_OF_RESOURCES There are not enough system > resources to modify > + the attributes. > + @retval RETURN_UNSUPPORTED Cannot modify the attributes of give= n > memory. > + > +**/ > +RETURN_STATUS > +EFIAPI > +ConvertMemoryPageAttributes ( > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINT64 Length, > + IN UINT64 Attributes > + ) > +{ > + UINT64 *PageEntry; > + PAGE_ATTRIBUTE PageAttribute; > + RETURN_STATUS Status; > + EFI_PHYSICAL_ADDRESS MaximumAddress; > + > + if (Length =3D=3D 0 || > + (BaseAddress & (SIZE_4KB - 1)) !=3D 0 || > + (Length & (SIZE_4KB - 1)) !=3D 0) { > + > + ASSERT (Length > 0); > + ASSERT ((BaseAddress & (SIZE_4KB - 1)) =3D=3D 0); > + ASSERT ((Length & (SIZE_4KB - 1)) =3D=3D 0); > + > + return RETURN_INVALID_PARAMETER; > + } > + > + MaximumAddress =3D (EFI_PHYSICAL_ADDRESS)MAX_UINT32; if > (BaseAddress > > + MaximumAddress || > + Length > MaximumAddress || > + (BaseAddress > MaximumAddress - (Length - 1))) { > + return RETURN_UNSUPPORTED; > + } > + > + // > + // Below logic is to check 2M/4K page to make sure we do not waste > memory. > + // > + while (Length !=3D 0) { > + PageEntry =3D GetPageTableEntry (BaseAddress, &PageAttribute); > + if (PageEntry =3D=3D NULL) { > + return RETURN_UNSUPPORTED; > + } > + > + if (PageAttribute !=3D Page4K) { > + Status =3D SplitPage (PageEntry, PageAttribute, Page4K, FALSE); > + if (RETURN_ERROR (Status)) { > + return Status; > + } > + // > + // Do it again until the page is 4K. > + // > + continue; > + } > + > + // > + // Just take care of 'present' bit for Stack Guard. > + // > + if ((Attributes & IA32_PG_P) !=3D 0) { > + *PageEntry |=3D (UINT64)IA32_PG_P; > + } else { > + *PageEntry &=3D ~((UINT64)IA32_PG_P); > + } > + > + // > + // Convert success, move to next > + // > + BaseAddress +=3D SIZE_4KB; > + Length -=3D SIZE_4KB; > + } > + > + return RETURN_SUCCESS; > +} > + > +/** > + Get maximum size of page memory supported by current processor. > + > + @retval Page1G If processor supports 1G page and PML4. > + @retval Page2M For all other situations. > + > +**/ > +PAGE_ATTRIBUTE > +GetMaxMemoryPage ( > + IN PAGE_ATTRIBUTE TopLevelType > + ) > +{ > + UINT32 RegEax; > + UINT32 RegEdx; > + > + if (TopLevelType =3D=3D Page512G) { > + AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); > + if (RegEax >=3D CPUID_EXTENDED_CPU_SIG) { > + AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx); > + if ((RegEdx & BIT26) !=3D 0) { > + return Page1G; > + } > + } > + } > + > + return Page2M; > +} > + > +/** > + Create PML4 or PAE page table. > + > + @return The address of page table. > + > +**/ > +UINTN > +CreatePageTable ( > + VOID > + ) > +{ > + RETURN_STATUS Status; > + UINTN PhysicalAddressBits; > + UINTN NumberOfEntries; > + PAGE_ATTRIBUTE TopLevelPageAttr; > + UINTN PageTable; > + PAGE_ATTRIBUTE MaxMemoryPage; > + UINTN Index; > + UINT64 AddressEncMask; > + UINT64 *PageEntry; > + EFI_PHYSICAL_ADDRESS PhysicalAddress; > + > + TopLevelPageAttr =3D (PAGE_ATTRIBUTE)GetPageTableTopLevelType (); > + PhysicalAddressBits =3D GetPhysicalAddressWidth (); NumberOfEntries = =3D > + (UINTN)1 << (PhysicalAddressBits - > + > + mPageAttributeTable[TopLevelPageAttr].AddressBitOffset); > + > + PageTable =3D (UINTN) AllocatePageTableMemory (1); if (PageTable =3D= =3D 0) > + { > + return 0; > + } > + > + AddressEncMask =3D PcdGet64 (PcdPteMemoryEncryptionAddressOrMask); > + AddressEncMask &=3D > mPageAttributeTable[TopLevelPageAttr].AddressMask; > + MaxMemoryPage =3D GetMaxMemoryPage (TopLevelPageAttr); PageEntry > =3D > + (UINT64 *)PageTable; > + > + PhysicalAddress =3D 0; > + for (Index =3D 0; Index < NumberOfEntries; ++Index) { > + *PageEntry =3D PhysicalAddress | AddressEncMask | > + PAGE_ATTRIBUTE_BITS; > + > + // > + // Split the top page table down to the maximum page size supported > + // > + if (MaxMemoryPage < TopLevelPageAttr) { > + Status =3D SplitPage(PageEntry, TopLevelPageAttr, MaxMemoryPage, > TRUE); > + ASSERT_EFI_ERROR (Status); > + } > + > + if (TopLevelPageAttr =3D=3D Page1G) { > + // > + // PDPTE[2:1] (PAE Paging) must be 0. SplitPage() might change the= m to > 1. > + // > + *PageEntry &=3D ~(UINT64)(IA32_PG_RW | IA32_PG_U); > + } > + > + PageEntry +=3D 1; > + PhysicalAddress +=3D mPageAttributeTable[TopLevelPageAttr].Length; > + } > + > + > + return PageTable; > +} > + > +/** > + Setup page tables and make them work. > + > +**/ > +VOID > +EnablePaging ( > + VOID > + ) > +{ > + UINTN PageTable; > + > + PageTable =3D CreatePageTable (); > + ASSERT (PageTable !=3D 0); > + if (PageTable !=3D 0) { > + AsmWriteCr3(PageTable); > + AsmWriteCr4 (AsmReadCr4 () | BIT5); // CR4.PAE > + AsmWriteCr0 (AsmReadCr0 () | BIT31); // CR0.PG > + } > +} > + > +/** > + Get the base address of current AP's stack. > + > + This function is called in AP's context and assumes that whole > + calling stacks (till this function) consumed by AP's wakeup procedure = will > not exceed 4KB. > + > + PcdCpuApStackSize must be configured with value taking the Guard page > + into account. > + > + @param[in,out] Buffer The pointer to private data buffer. > + > +**/ > +VOID > +EFIAPI > +GetStackBase ( > + IN OUT VOID *Buffer > + ) > +{ > + EFI_PHYSICAL_ADDRESS StackBase; > + > + StackBase =3D (EFI_PHYSICAL_ADDRESS)(UINTN)&StackBase; > + StackBase +=3D BASE_4KB; > + StackBase &=3D ~((EFI_PHYSICAL_ADDRESS)BASE_4KB - 1); StackBase -=3D > + PcdGet32(PcdCpuApStackSize); > + > + *(EFI_PHYSICAL_ADDRESS *)Buffer =3D StackBase; } > + > +/** > + Setup stack Guard page at the stack base of each processor. BSP and > +APs have > + different way to get stack base address. > + > +**/ > +VOID > +SetupStackGuardPage ( > + VOID > + ) > +{ > + EFI_PEI_HOB_POINTERS Hob; > + EFI_PHYSICAL_ADDRESS StackBase; > + UINTN NumberOfProcessors; > + UINTN Bsp; > + UINTN Index; > + > + // > + // One extra page at the bottom of the stack is needed for Guard page. > + // > + if (PcdGet32(PcdCpuApStackSize) <=3D EFI_PAGE_SIZE) { > + DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack > Guard!\n")); > + ASSERT (FALSE); > + } > + > + MpInitLibGetNumberOfProcessors(&NumberOfProcessors, NULL); > + MpInitLibWhoAmI (&Bsp); for (Index =3D 0; Index < NumberOfProcessors; > + ++Index) { > + if (Index =3D=3D Bsp) { > + Hob.Raw =3D GetHobList (); > + while ((Hob.Raw =3D GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, > Hob.Raw)) !=3D NULL) { > + if (CompareGuid (&gEfiHobMemoryAllocStackGuid, > + &(Hob.MemoryAllocationStack->AllocDescriptor.Na= me))) { > + StackBase =3D Hob.MemoryAllocationStack- > >AllocDescriptor.MemoryBaseAddress; > + break; > + } > + Hob.Raw =3D GET_NEXT_HOB (Hob); > + } > + } else { > + // > + // Ask AP to return is stack base address. > + // > + MpInitLibStartupThisAP(GetStackBase, Index, NULL, 0, (VOID > *)&StackBase, NULL); > + } > + // > + // Set Guard page at stack base address. > + // > + ConvertMemoryPageAttributes(StackBase, EFI_PAGE_SIZE, 0); > + DEBUG ((DEBUG_INFO, "Stack Guard set at %lx [cpu%lu]!\n", > + (UINT64)StackBase, (UINT64)Index)); } > + > + // > + // Publish the changes of page table. > + // > + CpuFlushTlb (); > +} > + > +/** > + Enabl/setup stack guard for each processor if PcdCpuStackGuard is set = to > TRUE. > + > + Doing this in the memory-discovered callback is to make sure the > + Stack Guard feature to cover as most PEI code as possible. > + > + @param[in] PeiServices General purpose services available to = every > PEIM. > + @param[in] NotifyDescriptor The notification structure this PEIM > registered on install. > + @param[in] Ppi The memory discovered PPI. Not used. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval others There's error in MP initialization. > +**/ > +EFI_STATUS > +EFIAPI > +MemoryDiscoveredPpiNotifyCallback ( > + IN EFI_PEI_SERVICES **PeiServices, > + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, > + IN VOID *Ppi > + ) > +{ > + EFI_STATUS Status; > + BOOLEAN InitStackGuard; > + > + // > + // Paging must be setup first. Otherwise the exception TSS setup > + during MP // initialization later will not contain paging information > + and then fail // the task switch (for the sake of stack switch). > + // > + InitStackGuard =3D FALSE; > + if (IsIa32PaeSupported () && PcdGetBool (PcdCpuStackGuard)) { > + EnablePaging (); > + InitStackGuard =3D TRUE; > + } > + > + Status =3D InitializeCpuMpWorker ((CONST EFI_PEI_SERVICES > + **)PeiServices); ASSERT_EFI_ERROR (Status); > + > + if (InitStackGuard) { > + SetupStackGuardPage (); > + } > + > + return Status; > +} > + > -- > 2.16.2.windows.1