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.31; helo=mga06.intel.com; envelope-from=jiewen.yao@intel.com; receiver=edk2-devel@lists.01.org Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) (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 985212035BB16 for ; Wed, 22 Nov 2017 21:45:53 -0800 (PST) Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 22 Nov 2017 21:50:10 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.44,440,1505804400"; d="scan'208";a="5054471" Received: from fmsmsx106.amr.corp.intel.com ([10.18.124.204]) by fmsmga004.fm.intel.com with ESMTP; 22 Nov 2017 21:50:10 -0800 Received: from fmsmsx119.amr.corp.intel.com (10.18.124.207) by FMSMSX106.amr.corp.intel.com (10.18.124.204) with Microsoft SMTP Server (TLS) id 14.3.319.2; Wed, 22 Nov 2017 21:50:10 -0800 Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by FMSMSX119.amr.corp.intel.com (10.18.124.207) with Microsoft SMTP Server (TLS) id 14.3.319.2; Wed, 22 Nov 2017 21:50:09 -0800 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.175]) by SHSMSX151.ccr.corp.intel.com ([169.254.3.218]) with mapi id 14.03.0319.002; Thu, 23 Nov 2017 13:50:07 +0800 From: "Yao, Jiewen" To: "Wang, Jian J" , "edk2-devel@lists.01.org" CC: "Zeng, Star" , "Dong, Eric" , "Kinney, Michael D" Thread-Topic: [PATCH v2 7/8] UefiCpuPkg/CpuExceptionHandlerLib: Add stack switch support Thread-Index: AQHTY25fasIJD8yp+ESaspdkZc+2NKMhdfOQ Date: Thu, 23 Nov 2017 05:50:05 +0000 Message-ID: <74D8A39837DF1E4DA445A8C0B3885C503AA292EF@shsmsx102.ccr.corp.intel.com> References: <20171122084548.6564-1-jian.j.wang@intel.com> <20171122084548.6564-8-jian.j.wang@intel.com> In-Reply-To: <20171122084548.6564-8-jian.j.wang@intel.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiOGQwMGI0OWQtZDQ3MS00Yjk2LTljZjgtM2Q3YmYyZmZlYjM1IiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX0lDIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjIuNS4xOCIsIlRydXN0ZWRMYWJlbEhhc2giOiJzWVQrYjlDWGtaRlRKVzVKUmRmK2tDeUQxNU1WcVZicGx6eUNaWEVpaVZNTlNTbGpUWFFlUTNZK3BhQ3FXOVVIIn0= x-ctpclassification: CTP_IC dlp-product: dlpe-windows dlp-version: 11.0.0.116 dlp-reaction: no-action x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH v2 7/8] UefiCpuPkg/CpuExceptionHandlerLib: Add stack switch support 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: Thu, 23 Nov 2017 05:45:54 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Some thought: 1) I found InitializeCpuExceptionStackSwitchHandlers() is only implemented = in DxeException.c. What about Pei/Smm instance? I think it is OK to not implement it at this moment. But we need make sure = no architecture issue if we want to enable it some time later. 2) #define IA32_GDT_TYPE_TSS 0x9 This is generic, can we move to BaseLib.h? Thank you Yao Jiewen > -----Original Message----- > From: Wang, Jian J > Sent: Wednesday, November 22, 2017 4:46 PM > To: edk2-devel@lists.01.org > Cc: Zeng, Star ; Dong, Eric ; Y= ao, > Jiewen ; Kinney, Michael D > > Subject: [PATCH v2 7/8] UefiCpuPkg/CpuExceptionHandlerLib: Add stack swit= ch > support >=20 > > v2: > > a. Move common TSS structure and API definitions to BaseLib.h > > b. Add EXCEPTION_STACK_SWITCH_DATA to convery data used to setup > stack > > switch. This can avoid allocating memory for it in this library. > > c. Add globals to reserve memory for stack switch initialized in ear= ly > > phase of DXE core. > > d. Remove the filter code used to exclude boot modes which doesn't > support > > memory allocation because those memory can passed in by parameter > now. > > e. Remove the nasm macro to define exception handler one by one and > add a > > function to return the start address of each handler. >=20 > If Stack Guard is enabled and there's really a stack overflow happened du= ring > boot, a Page Fault exception will be triggered. Because the stack is out = of > usage, the exception handler, which shares the stack with normal UEFI dri= ver, > cannot be executed and cannot dump the processor information. >=20 > Without those information, it's very difficult for the BIOS developers lo= cate > the root cause of stack overflow. And without a workable stack, the devel= oper > cannot event use single step to debug the UEFI driver with JTAG debugger. >=20 > In order to make sure the exception handler to execute normally after sta= ck > overflow. We need separate stacks for exception handlers in case of unusa= ble > stack. >=20 > IA processor allows to switch to a new stack during handling interrupt an= d > exception. But X64 and IA32 provides different ways to make it. X64 provi= des > interrupt stack table (IST) to allow maximum 7 different exceptions to ha= ve > new stack for its handler. IA32 doesn't have IST mechanism and can only u= se > task gate to do it since task switch allows to load a new stack through i= ts > task-state segment (TSS). >=20 > Cc: Star Zeng > Cc: Eric Dong > Cc: Jiewen Yao > Cc: Michael Kinney > Suggested-by: Ayellet Wolman > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Jian J Wang > --- > .../CpuExceptionHandlerLib/CpuExceptionCommon.h | 50 +++ > .../DxeCpuExceptionHandlerLib.inf | 6 + > .../Library/CpuExceptionHandlerLib/DxeException.c | 53 ++- > .../Ia32/ArchExceptionHandler.c | 167 +++++++++ > .../Ia32/ArchInterruptDefs.h | 8 + > .../Ia32/ExceptionTssEntryAsm.nasm | 398 > +++++++++++++++++++++ > .../PeiCpuExceptionHandlerLib.inf | 1 + > .../SecPeiCpuExceptionHandlerLib.inf | 1 + > .../SmmCpuExceptionHandlerLib.inf | 1 + > .../X64/ArchExceptionHandler.c | 133 +++++++ > .../CpuExceptionHandlerLib/X64/ArchInterruptDefs.h | 3 + > 11 files changed, 820 insertions(+), 1 deletion(-) > create mode 100644 > UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm >=20 > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h > index 740a58828b..30334105d2 100644 > --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h > +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h > @@ -48,6 +48,32 @@ > 0xb21d9148, 0x9211, 0x4d8f, { 0xad, 0xd3, 0x66, 0xb1, 0x89, 0xc9, 0x= 2c, 0x83 } > \ > } >=20 > +#define CPU_STACK_SWITCH_EXCEPTION_NUMBER \ > + FixedPcdGetSize (PcdCpuStackSwitchExceptionList) > + > +#define CPU_STACK_SWITCH_EXCEPTION_LIST \ > + FixedPcdGetPtr (PcdCpuStackSwitchExceptionList) > + > +#define CPU_KNOWN_GOOD_STACK_SIZE \ > + FixedPcdGet32 (PcdCpuKnownGoodStackSize) > + > +#define CPU_TSS_GDT_SIZE (SIZE_2KB + CPU_TSS_DESC_SIZE + CPU_TSS_SIZE) > + > +#define IA32_GDT_TYPE_TSS 0x9 > +#define IA32_GDT_ALIGNMENT 8 > + > +typedef struct { > + UINTN StackTop; > + UINTN StackSize; > + UINT8 *Exceptions; > + UINTN ExceptionNumber; > + IA32_IDT_GATE_DESCRIPTOR *IdtTable; > + IA32_SEGMENT_DESCRIPTOR *GdtTable; > + UINTN GdtSize; > + IA32_TSS_DESCRIPTOR *TssDesc; > + IA32_TASK_STATE_SEGMENT *Tss; > +} EXCEPTION_STACK_SWITCH_DATA; > + > // > // Record exception handler information > // > @@ -288,5 +314,29 @@ CommonExceptionHandlerWorker ( > IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData > ); >=20 > +/** > + Setup separate stack for specific exceptions. > + > + @param[in] IdtTable IDT table base. > +**/ > +EFI_STATUS > +EFIAPI > +ArchSetupExcpetionStack ( > + IN EXCEPTION_STACK_SWITCH_DATA *StackSwitchData > + ); > + > +/** > + Return address map of exception handler template so that C code can > generate > + exception tables. The template is only for exceptions using task gate = instead > + of interrupt gate. > + > + @param AddressMap Pointer to a buffer where the address map is > returned. > +**/ > +VOID > +EFIAPI > +AsmGetTssTemplateMap ( > + OUT EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap > + ); > + > #endif >=20 > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf > index f4a8d01c80..58e55a8a2e 100644 > --- > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf > +++ > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf > @@ -30,6 +30,7 @@ > [Sources.Ia32] > Ia32/ExceptionHandlerAsm.asm > Ia32/ExceptionHandlerAsm.nasm > + Ia32/ExceptionTssEntryAsm.nasm > Ia32/ExceptionHandlerAsm.S > Ia32/ArchExceptionHandler.c > Ia32/ArchInterruptDefs.h > @@ -47,6 +48,11 @@ > PeiDxeSmmCpuException.c > DxeException.c >=20 > +[Pcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard > + gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList > + gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize > + > [Packages] > MdePkg/MdePkg.dec > MdeModulePkg/MdeModulePkg.dec > diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c > index 31febec976..c0b2c615aa 100644 > --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c > +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c > @@ -25,6 +25,10 @@ UINTN mEnabledInterruptNum =3D > 0; >=20 > EXCEPTION_HANDLER_DATA mExceptionHandlerData; >=20 > +UINT8 > mNewStack[CPU_STACK_SWITCH_EXCEPTION_NUMBER * > + CPU_KNOWN_GOOD_STACK_SIZE] > =3D {0}; > +UINT8 mNewGdt[CPU_TSS_GDT_SIZE] =3D {0}; > + > /** > Common exception handler. >=20 > @@ -63,10 +67,34 @@ InitializeCpuExceptionHandlers ( > IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL > ) > { > + EFI_STATUS Status; > + EXCEPTION_STACK_SWITCH_DATA StackSwitchData; > + IA32_DESCRIPTOR Idtr; > + IA32_DESCRIPTOR Gdtr; > + > mExceptionHandlerData.ReservedVectors =3D > mReservedVectorsData; > mExceptionHandlerData.ExternalInterruptHandler =3D > mExternalInterruptHandlerTable; > InitializeSpinLock (&mExceptionHandlerData.DisplayMessageSpinLock); > - return InitializeCpuExceptionHandlersWorker (VectorInfo, > &mExceptionHandlerData); > + Status =3D InitializeCpuExceptionHandlersWorker (VectorInfo, > &mExceptionHandlerData); > + if (!EFI_ERROR (Status) && PcdGetBool (PcdCpuStackGuard)) { > + AsmReadIdtr (&Idtr); > + AsmReadGdtr (&Gdtr); > + > + StackSwitchData.StackTop =3D (UINTN)mNewStack; > + StackSwitchData.StackSize =3D CPU_KNOWN_GOOD_STACK_SIZE; > + StackSwitchData.Exceptions =3D CPU_STACK_SWITCH_EXCEPTION_LIST; > + StackSwitchData.ExceptionNumber =3D > CPU_STACK_SWITCH_EXCEPTION_NUMBER; > + StackSwitchData.IdtTable =3D (IA32_IDT_GATE_DESCRIPTOR *)Idtr.Base; > + StackSwitchData.GdtTable =3D (IA32_SEGMENT_DESCRIPTOR *)mNewGdt; > + StackSwitchData.GdtSize =3D sizeof (mNewGdt); > + StackSwitchData.TssDesc =3D (IA32_TSS_DESCRIPTOR *)(mNewGdt + > Gdtr.Limit + 1); > + StackSwitchData.Tss =3D (IA32_TASK_STATE_SEGMENT *)(mNewGdt + > Gdtr.Limit + 1 + > + > CPU_TSS_DESC_SIZE); > + Status =3D InitializeCpuExceptionStackSwitchHandlers ( > + &StackSwitchData > + ); > + } > + return Status; > } >=20 > /** > @@ -197,3 +225,26 @@ RegisterCpuInterruptHandler ( > { > return RegisterCpuInterruptHandlerWorker (InterruptType, InterruptHand= ler, > &mExceptionHandlerData); > } > + > +/** > + Setup separate stack for given exceptions. This is required by > + PcdCpuStackGuard feature. > + > + Note: For IA32 processor, StackSwitchData is a required parameter. > + > + @param[in] StackSwitchData Pointer to data required for setuping = up > + stack switch. > + > + @retval EFI_SUCCESS The exceptions have been successfully > + initialized. > + @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid > content. > + > +**/ > +EFI_STATUS > +EFIAPI > +InitializeCpuExceptionStackSwitchHandlers ( > + IN VOID *StackSwitchData OPTIONAL > + ) > +{ > + return ArchSetupExcpetionStack (StackSwitchData); > +} > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c > index f2c39eb193..0aaf794795 100644 > --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler= .c > +++ > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c > @@ -107,6 +107,173 @@ ArchRestoreExceptionContext ( > SystemContext.SystemContextIa32->ExceptionData =3D > ReservedVectors[ExceptionType].ExceptionData; > } >=20 > +/** > + Setup separate stack for given exceptions. > + > + @param[in] StackSwitchData Pointer to data required for setupin= g > up > + stack switch. > + @retval EFI_SUCCESS The exceptions have been successfully > + initialized. > + @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid > content. > + > +**/ > +EFI_STATUS > +EFIAPI > +ArchSetupExcpetionStack ( > + IN EXCEPTION_STACK_SWITCH_DATA *StackSwitchData > + ) > +{ > + IA32_DESCRIPTOR Gdtr; > + IA32_DESCRIPTOR Idtr; > + IA32_IDT_GATE_DESCRIPTOR *IdtTable; > + IA32_TSS_DESCRIPTOR *TssDesc; > + IA32_TASK_STATE_SEGMENT *Tss; > + UINTN StackTop; > + UINTN Index; > + UINTN Vector; > + UINTN TssBase; > + UINTN GdtSize; > + EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap; > + > + if (StackSwitchData =3D=3D NULL || > + StackSwitchData->StackTop =3D=3D 0 || > + StackSwitchData->StackSize =3D=3D 0 || > + StackSwitchData->Exceptions =3D=3D NULL || > + StackSwitchData->ExceptionNumber =3D=3D 0 || > + StackSwitchData->GdtTable =3D=3D NULL || > + StackSwitchData->IdtTable =3D=3D NULL || > + StackSwitchData->TssDesc =3D=3D NULL || > + StackSwitchData->Tss =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The caller is responsible for that the GDT table, no matter the exi= sting > + // one or newly allocated, has enough space to hold descriptors for ex= ception > + // task-state segments. > + // > + if (((UINTN)StackSwitchData->GdtTable & (IA32_GDT_ALIGNMENT - 1)) !=3D= 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((UINTN)StackSwitchData->TssDesc < (UINTN)(StackSwitchData->GdtTabl= e)) > { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((UINTN)StackSwitchData->TssDesc >=3D > + ((UINTN)(StackSwitchData->GdtTable) + StackSwitchData->GdtSize= )) > { > + return EFI_INVALID_PARAMETER; > + } > + > + GdtSize =3D (UINTN)StackSwitchData->TssDesc - > + (UINTN)(StackSwitchData->GdtTable) + > + sizeof (IA32_TSS_DESCRIPTOR) * > + (StackSwitchData->ExceptionNumber + 1); > + if (GdtSize > StackSwitchData->GdtSize) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Initialize new GDT table and/or IDT table, if any > + // > + AsmReadIdtr (&Idtr); > + AsmReadGdtr (&Gdtr); > + if ((UINTN)StackSwitchData->GdtTable !=3D Gdtr.Base) { > + CopyMem (StackSwitchData->GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + = 1); > + Gdtr.Base =3D (UINTN)StackSwitchData->GdtTable; > + Gdtr.Limit =3D (UINT16)StackSwitchData->GdtSize - 1; > + } > + > + if ((UINTN)StackSwitchData->IdtTable !=3D Idtr.Base) { > + Idtr.Base =3D (UINTN)StackSwitchData->IdtTable; > + } > + > + // > + // Fixup current task descriptor. Task-state segment for current task = will > + // be filled by processor during task switching. > + // > + TssDesc =3D StackSwitchData->TssDesc; > + Tss =3D StackSwitchData->Tss; > + > + TssBase =3D (UINTN)Tss; > + TssDesc->Bits.LimitLow =3D sizeof(IA32_TASK_STATE_SEGMENT) - 1; > + TssDesc->Bits.BaseLow =3D (UINT16)TssBase; > + TssDesc->Bits.BaseMid =3D (UINT8)(TssBase >> 16); > + TssDesc->Bits.Type =3D IA32_GDT_TYPE_TSS; > + TssDesc->Bits.P =3D 1; > + TssDesc->Bits.LimitHigh =3D 0; > + TssDesc->Bits.BaseHigh =3D (UINT8)(TssBase >> 24); > + > + // > + // Fixup exception task descriptor and task-state segment > + // > + AsmGetTssTemplateMap (&TemplateMap); > + StackTop =3D StackSwitchData->StackTop - CPU_STACK_ALIGNMENT; > + StackTop =3D (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT); > + IdtTable =3D StackSwitchData->IdtTable; > + for (Index =3D 0; Index < StackSwitchData->ExceptionNumber; ++Index) { > + TssDesc +=3D 1; > + Tss +=3D 1; > + > + // > + // Fixup TSS descriptor > + // > + TssBase =3D (UINTN)Tss; > + > + TssDesc->Bits.LimitLow =3D sizeof(IA32_TASK_STATE_SEGMENT) - 1; > + TssDesc->Bits.BaseLow =3D (UINT16)TssBase; > + TssDesc->Bits.BaseMid =3D (UINT8)(TssBase >> 16); > + TssDesc->Bits.Type =3D IA32_GDT_TYPE_TSS; > + TssDesc->Bits.P =3D 1; > + TssDesc->Bits.LimitHigh =3D 0; > + TssDesc->Bits.BaseHigh =3D (UINT8)(TssBase >> 24); > + > + // > + // Fixup TSS > + // > + Vector =3D StackSwitchData->Exceptions[Index]; > + Tss->EIP =3D (UINT32)(TemplateMap.ExceptionStart > + + Vector * > TemplateMap.ExceptionStubHeaderSize); > + Tss->EFLAGS =3D 0x2; > + Tss->ESP =3D StackTop; > + Tss->CR3 =3D AsmReadCr3 (); > + Tss->ES =3D AsmReadEs (); > + Tss->CS =3D AsmReadCs (); > + Tss->SS =3D AsmReadSs (); > + Tss->DS =3D AsmReadDs (); > + Tss->FS =3D AsmReadFs (); > + Tss->GS =3D AsmReadGs (); > + > + StackTop -=3D StackSwitchData->StackSize; > + > + // > + // Update IDT to use Task Gate for given exception > + // > + IdtTable[Vector].Bits.OffsetLow =3D 0; > + IdtTable[Vector].Bits.Selector =3D (UINT16)((UINTN)TssDesc - Gdtr.= Base); > + IdtTable[Vector].Bits.Reserved_0 =3D 0; > + IdtTable[Vector].Bits.GateType =3D IA32_IDT_GATE_TYPE_TASK; > + IdtTable[Vector].Bits.OffsetHigh =3D 0; > + } > + > + // > + // Publish GDT > + // > + AsmWriteGdtr (&Gdtr); > + > + // > + // Load current task > + // > + AsmWriteTr ((UINT16)((UINTN)StackSwitchData->TssDesc - Gdtr.Base)); > + > + // > + // Publish IDT > + // > + AsmWriteIdtr (&Idtr); > + > + return EFI_SUCCESS; > +} > + > /** > Display processor context. >=20 > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h > index a8d3556a80..d9ded5977f 100644 > --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h > +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h > @@ -41,4 +41,12 @@ typedef struct { > UINT8 HookAfterStubHeaderCode[HOOKAFTER_STUB_SIZE]; > } RESERVED_VECTORS_DATA; >=20 > +#define CPU_TSS_DESC_SIZE \ > + (sizeof (IA32_TSS_DESCRIPTOR) * \ > + (PcdGetSize (PcdCpuStackSwitchExceptionList) + 1)) > + > +#define CPU_TSS_SIZE \ > + (sizeof (IA32_TASK_STATE_SEGMENT) * \ > + (PcdGetSize (PcdCpuStackSwitchExceptionList) + 1)) > + > #endif > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nas > m > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nas > m > new file mode 100644 > index 0000000000..62bcedea1a > --- /dev/null > +++ > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nas > m > @@ -0,0 +1,398 @@ > +;-----------------------------------------------------------------------= ------- ; > +; Copyright (c) 2017, 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. > +; > +; Module Name: > +; > +; ExceptionTssEntryAsm.Asm > +; > +; Abstract: > +; > +; IA32 CPU Exception Handler with Separate Stack > +; > +; Notes: > +; > +;-----------------------------------------------------------------------= ------- > + > +; > +; IA32 TSS Memory Layout Description > +; > +struc IA32_TSS > + resw 1 > + resw 1 > + .ESP0: resd 1 > + .SS0: resw 1 > + resw 1 > + .ESP1: resd 1 > + .SS1: resw 1 > + resw 1 > + .ESP2: resd 1 > + .SS2: resw 1 > + resw 1 > + ._CR3: resd 1 > + .EIP: resd 1 > + .EFLAGS: resd 1 > + ._EAX: resd 1 > + ._ECX: resd 1 > + ._EDX: resd 1 > + ._EBX: resd 1 > + ._ESP: resd 1 > + ._EBP: resd 1 > + ._ESI: resd 1 > + ._EDI: resd 1 > + ._ES: resw 1 > + resw 1 > + ._CS: resw 1 > + resw 1 > + ._SS: resw 1 > + resw 1 > + ._DS: resw 1 > + resw 1 > + ._FS: resw 1 > + resw 1 > + ._GS: resw 1 > + resw 1 > + .LDT: resw 1 > + resw 1 > + resw 1 > + resw 1 > +endstruc > + > +; > +; CommonExceptionHandler() > +; > +extern ASM_PFX(CommonExceptionHandler) > + > +SECTION .data > + > +SECTION .text > + > +ALIGN 8 > + > +; > +; Exception handler stub table > +; > +AsmExceptionEntryBegin: > +%assign Vector 0 > +%rep 32 > + > +DoIret%[Vector]: > + iretd > +ASM_PFX(ExceptionTaskSwtichEntry%[Vector]): > + db 0x6a ; push #VectorNum > + db %[Vector] > + mov eax, ASM_PFX(CommonTaskSwtichEntryPoint) > + call eax > + mov esp, eax ; Restore stack top > + jmp DoIret%[Vector] > + > +%assign Vector Vector+1 > +%endrep > +AsmExceptionEntryEnd: > + > +; > +; Common part of exception handler > +; > +global ASM_PFX(CommonTaskSwtichEntryPoint) > +ASM_PFX(CommonTaskSwtichEntryPoint): > + ; > + ; Stack: > + ; +---------------------+ <-- EBP - 8 > + ; + TSS Base + > + ; +---------------------+ <-- EBP - 4 > + ; + CPUID.EDX + > + ; +---------------------+ <-- EBP > + ; + EIP + > + ; +---------------------+ <-- EBP + 4 > + ; + Vector Number + > + ; +---------------------+ <-- EBP + 8 > + ; + Error Code + > + ; +---------------------+ > + ; > + > + mov ebp, esp ; Stack frame > + > +; Use CPUID to determine if FXSAVE/FXRESTOR and DE are supported > + mov eax, 1 > + cpuid > + push edx > + > +; Get TSS base of interrupted task through PreviousTaskLink field in > +; current TSS base > + sub esp, 8 > + sgdt [esp + 2] > + mov eax, [esp + 4] ; GDT base > + add esp, 8 > + > + xor ebx, ebx > + str bx ; Current TR > + > + mov ecx, [eax + ebx + 2] > + shl ecx, 8 > + mov cl, [eax + ebx + 7] > + ror ecx, 8 ; ecx =3D Current TSS base > + push ecx ; keep it in stack for later use > + > + movzx ebx, word [ecx] ; Previous Task Link > + mov ecx, [eax + ebx + 2] > + shl ecx, 8 > + mov cl, [eax + ebx + 7] > + ror ecx, 8 ; ecx =3D Previous TSS base > + > +; > +; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of > EFI_SYSTEM_CONTEXT_IA32 > +; is 16-byte aligned > +; > + and esp, 0xfffffff0 > + sub esp, 12 > + > +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; > + push dword [ecx + IA32_TSS._EAX] > + push dword [ecx + IA32_TSS._ECX] > + push dword [ecx + IA32_TSS._EDX] > + push dword [ecx + IA32_TSS._EBX] > + push dword [ecx + IA32_TSS._ESP] > + push dword [ecx + IA32_TSS._EBP] > + push dword [ecx + IA32_TSS._ESI] > + push dword [ecx + IA32_TSS._EDI] > + > +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; > + movzx eax, word [ecx + IA32_TSS._SS] > + push eax > + movzx eax, word [ecx + IA32_TSS._CS] > + push eax > + movzx eax, word [ecx + IA32_TSS._DS] > + push eax > + movzx eax, word [ecx + IA32_TSS._ES] > + push eax > + movzx eax, word [ecx + IA32_TSS._FS] > + push eax > + movzx eax, word [ecx + IA32_TSS._GS] > + push eax > + > +;; UINT32 Eip; > + push dword [ecx + IA32_TSS.EIP] > + > +;; UINT32 Gdtr[2], Idtr[2]; > + sub esp, 8 > + sidt [esp] > + mov eax, [esp + 2] > + xchg eax, [esp] > + and eax, 0xFFFF > + mov [esp+4], eax > + > + sub esp, 8 > + sgdt [esp] > + mov eax, [esp + 2] > + xchg eax, [esp] > + and eax, 0xFFFF > + mov [esp+4], eax > + > +;; UINT32 Ldtr, Tr; > + mov eax, ebx ; ebx still keeps selector of interrupted task > + push eax > + movzx eax, word [ecx + IA32_TSS.LDT] > + push eax > + > +;; UINT32 EFlags; > + push dword [ecx + IA32_TSS.EFLAGS] > + > +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; > + mov eax, cr4 > + push eax ; push cr4 firstly > + > + mov edx, [ebp - 4] ; cpuid.edx > + test edx, BIT24 ; Test for FXSAVE/FXRESTOR support > + jz .1 > + or eax, BIT9 ; Set CR4.OSFXSR > +.1: > + test edx, BIT2 ; Test for Debugging Extensions support > + jz .2 > + or eax, BIT3 ; Set CR4.DE > +.2: > + mov cr4, eax > + > + mov eax, cr3 > + push eax > + mov eax, cr2 > + push eax > + xor eax, eax > + push eax > + mov eax, cr0 > + push eax > + > +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; > + mov eax, dr7 > + push eax > + mov eax, dr6 > + push eax > + mov eax, dr3 > + push eax > + mov eax, dr2 > + push eax > + mov eax, dr1 > + push eax > + mov eax, dr0 > + push eax > + > +;; FX_SAVE_STATE_IA32 FxSaveState; > +;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM) > +;; when executing fxsave/fxrstor instruction > + test edx, BIT24 ; Test for FXSAVE/FXRESTOR support. > + ; edx still contains result from CPUID above > + jz .3 > + clts > + sub esp, 512 > + mov edi, esp > + db 0xf, 0xae, 0x7 ;fxsave [edi] > +.3: > + > +;; UINT32 ExceptionData; > + push dword [ebp + 8] > + > +;; UEFI calling convention for IA32 requires that Direction flag in EFLA= Gs is clear > + cld > + > +;; call into exception handler > + mov esi, ecx ; Keep TSS base to avoid overwrite > + mov eax, ASM_PFX(CommonExceptionHandler) > + > +;; Prepare parameter and call > + mov edx, esp > + push edx ; EFI_SYSTEM_CONTEXT > + push dword [ebp + 4] ; EFI_EXCEPTION_TYPE (vector number) > + > + ; > + ; Call External Exception Handler > + ; > + call eax > + add esp, 8 ; Restore stack before calling > + mov ecx, esi ; Restore TSS base > + > +;; UINT32 ExceptionData; > + add esp, 4 > + > +;; FX_SAVE_STATE_IA32 FxSaveState; > + mov edx, [ebp - 4] ; cpuid.edx > + test edx, BIT24 ; Test for FXSAVE/FXRESTOR support > + jz .4 > + mov esi, esp > + db 0xf, 0xae, 0xe ; fxrstor [esi] > +.4: > + add esp, 512 > + > +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; > +;; Skip restoration of DRx registers to support debuggers > +;; that set breakpoints in interrupt/exception context > + add esp, 4 * 6 > + > +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; > + pop eax > + mov cr0, eax > + add esp, 4 ; not for Cr1 > + pop eax > + mov cr2, eax > + pop eax > + mov dword [ecx + IA32_TSS._CR3], eax > + pop eax > + mov cr4, eax > + > +;; UINT32 EFlags; > + pop dword [ecx + IA32_TSS.EFLAGS] > + mov ebx, dword [ecx + IA32_TSS.EFLAGS] > + btr ebx, 9 ; Do 'cli' > + mov dword [ecx + IA32_TSS.EFLAGS], ebx > + > +;; UINT32 Ldtr, Tr; > +;; UINT32 Gdtr[2], Idtr[2]; > +;; Best not let anyone mess with these particular registers... > + add esp, 24 > + > +;; UINT32 Eip; > + pop dword [ecx + IA32_TSS.EIP] > + > +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; > +;; NOTE - modified segment registers could hang the debugger... We > +;; could attempt to insulate ourselves against this possibility, > +;; but that poses risks as well. > +;; > + pop eax > +o16 mov [ecx + IA32_TSS._GS], ax > + pop eax > +o16 mov [ecx + IA32_TSS._FS], ax > + pop eax > +o16 mov [ecx + IA32_TSS._ES], ax > + pop eax > +o16 mov [ecx + IA32_TSS._DS], ax > + pop eax > +o16 mov [ecx + IA32_TSS._CS], ax > + pop eax > +o16 mov [ecx + IA32_TSS._SS], ax > + > +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; > + pop dword [ecx + IA32_TSS._EDI] > + pop dword [ecx + IA32_TSS._ESI] > + add esp, 4 ; not for ebp > + add esp, 4 ; not for esp > + pop dword [ecx + IA32_TSS._EBX] > + pop dword [ecx + IA32_TSS._EDX] > + pop dword [ecx + IA32_TSS._ECX] > + pop dword [ecx + IA32_TSS._EAX] > + > +; Set single step DB# to allow debugger to able to go back to the EIP > +; where the exception is triggered. > + > +;; Create return context for iretd in stub function > + mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer > + mov ebx, dword [ecx + IA32_TSS.EIP] > + mov [eax - 0xc], ebx ; create EIP in old sta= ck > + movzx ebx, word [ecx + IA32_TSS._CS] > + mov [eax - 0x8], ebx ; create CS in old stac= k > + mov ebx, dword [ecx + IA32_TSS.EFLAGS] > + bts ebx, 8 > + mov [eax - 0x4], ebx ; create eflags in old = stack > + mov dword [ecx + IA32_TSS.EFLAGS], ebx ; update eflags in old = TSS > + mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer > + sub eax, 0xc ; minus 12 byte > + mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer > + > +;; Replace the EIP of interrupted task with stub function > + mov eax, ASM_PFX(SingleStepStubFunction) > + mov dword [ecx + IA32_TSS.EIP], eax > + > + mov ecx, [ebp - 8] ; Get current TSS base > + mov eax, dword [ecx + IA32_TSS._ESP] ; Return current stack = top > + mov esp, ebp > + > + ret > + > +global ASM_PFX(SingleStepStubFunction) > +ASM_PFX(SingleStepStubFunction): > +; > +; we need clean TS bit in CR0 to execute > +; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions. > +; > + clts > + iretd > + > +global ASM_PFX(AsmGetTssTemplateMap) > +ASM_PFX(AsmGetTssTemplateMap): > + push ebp ; C prolog > + mov ebp, esp > + pushad > + > + mov ebx, dword [ebp + 0x8] > + mov dword [ebx], ASM_PFX(ExceptionTaskSwtichEntry0) > + mov dword [ebx + 0x4], (AsmExceptionEntryEnd - AsmExceptionEntryBegi= n) > / 32 > + mov dword [ebx + 0x8], 0 > + > + popad > + pop ebp > + ret > + > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf > index 75443288a9..4c0d435136 100644 > --- > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf > +++ > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf > @@ -30,6 +30,7 @@ > [Sources.Ia32] > Ia32/ExceptionHandlerAsm.asm > Ia32/ExceptionHandlerAsm.nasm > + Ia32/ExceptionTssEntryAsm.nasm > Ia32/ExceptionHandlerAsm.S > Ia32/ArchExceptionHandler.c > Ia32/ArchInterruptDefs.h > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.= i > nf > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.= i > nf > index d70a99c100..e5c03c16c9 100644 > --- > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.= i > nf > +++ > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.= i > nf > @@ -30,6 +30,7 @@ > [Sources.Ia32] > Ia32/ExceptionHandlerAsm.asm > Ia32/ExceptionHandlerAsm.nasm > + Ia32/ExceptionTssEntryAsm.nasm > Ia32/ExceptionHandlerAsm.S > Ia32/ArchExceptionHandler.c > Ia32/ArchInterruptDefs.h > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf > index 634ffcb21d..56b875b7c8 100644 > --- > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf > +++ > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf > @@ -30,6 +30,7 @@ > [Sources.Ia32] > Ia32/ExceptionHandlerAsm.asm > Ia32/ExceptionHandlerAsm.nasm > + Ia32/ExceptionTssEntryAsm.nasm > Ia32/ExceptionHandlerAsm.S > Ia32/ArchExceptionHandler.c > Ia32/ArchInterruptDefs.h > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c > index 65f0cff680..214aafcc13 100644 > --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.= c > +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.= c > @@ -112,6 +112,139 @@ ArchRestoreExceptionContext ( > SystemContext.SystemContextX64->ExceptionData =3D > ReservedVectors[ExceptionType].ExceptionData; > } >=20 > +/** > + Setup separate stack for given exceptions. > + > + @param[in] StackSwitchData Pointer to data required for setuping = up > + stack switch. > + > + @retval EFI_SUCCESS The exceptions have been successfully > + initialized. > + @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid > content. > + > +**/ > +EFI_STATUS > +EFIAPI > +ArchSetupExcpetionStack ( > + IN EXCEPTION_STACK_SWITCH_DATA *StackSwitchData > + ) > +{ > + IA32_DESCRIPTOR Gdtr; > + IA32_DESCRIPTOR Idtr; > + IA32_IDT_GATE_DESCRIPTOR *IdtTable; > + IA32_TSS_DESCRIPTOR *TssDesc; > + IA32_TASK_STATE_SEGMENT *Tss; > + UINTN StackTop; > + UINTN Index; > + UINTN TssBase; > + UINTN GdtSize; > + > + if (StackSwitchData =3D=3D NULL || > + StackSwitchData->StackTop =3D=3D 0 || > + StackSwitchData->StackSize =3D=3D 0 || > + StackSwitchData->Exceptions =3D=3D NULL || > + StackSwitchData->ExceptionNumber =3D=3D 0 || > + StackSwitchData->GdtTable =3D=3D NULL || > + StackSwitchData->IdtTable =3D=3D NULL || > + StackSwitchData->TssDesc =3D=3D NULL || > + StackSwitchData->Tss =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The caller is responsible for that the GDT table, no matter the exi= sting > + // one or newly allocated, has enough space to hold descriptors for ex= ception > + // task-state segments. > + // > + if (((UINTN)StackSwitchData->GdtTable & (IA32_GDT_ALIGNMENT - 1)) !=3D= 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((UINTN)StackSwitchData->TssDesc < (UINTN)(StackSwitchData->GdtTabl= e)) > { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((UINTN)StackSwitchData->TssDesc >=3D > + ((UINTN)(StackSwitchData->GdtTable) + StackSwitchData->GdtSize= )) > { > + return EFI_INVALID_PARAMETER; > + } > + > + GdtSize =3D (UINTN)StackSwitchData->TssDesc - > + (UINTN)(StackSwitchData->GdtTable) + > + sizeof (IA32_TSS_DESCRIPTOR); > + if (GdtSize > StackSwitchData->GdtSize) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Initialize new GDT table and/or IDT table, if any > + // > + AsmReadIdtr (&Idtr); > + AsmReadGdtr (&Gdtr); > + if ((UINTN)StackSwitchData->GdtTable !=3D Gdtr.Base) { > + CopyMem (StackSwitchData->GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + = 1); > + Gdtr.Base =3D (UINTN)StackSwitchData->GdtTable; > + Gdtr.Limit =3D (UINT16)GdtSize - 1; > + } > + > + if ((UINTN)StackSwitchData->IdtTable !=3D Idtr.Base) { > + Idtr.Base =3D (UINTN)StackSwitchData->IdtTable; > + } > + > + // > + // Fixup current task descriptor. Task-state segment for current task = will > + // be filled by processor during task switching. > + // > + TssDesc =3D StackSwitchData->TssDesc; > + Tss =3D StackSwitchData->Tss; > + > + TssBase =3D (UINTN)Tss; > + TssDesc->Bits.LimitLow =3D sizeof(IA32_TASK_STATE_SEGMENT) - 1; > + TssDesc->Bits.BaseLow =3D (UINT16)TssBase; > + TssDesc->Bits.BaseMidl =3D (UINT8)(TssBase >> 16); > + TssDesc->Bits.Type =3D IA32_GDT_TYPE_TSS; > + TssDesc->Bits.P =3D 1; > + TssDesc->Bits.LimitHigh =3D 0; > + TssDesc->Bits.BaseMidh =3D (UINT8)(TssBase >> 24); > + TssDesc->Bits.BaseHigh =3D (UINT32)(TssBase >> 32); > + > + // > + // Fixup exception task descriptor and task-state segment > + // > + StackTop =3D StackSwitchData->StackTop - CPU_STACK_ALIGNMENT; > + StackTop =3D (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT); > + IdtTable =3D StackSwitchData->IdtTable; > + for (Index =3D 0; Index < StackSwitchData->ExceptionNumber; ++Index) { > + // > + // Fixup IST > + // > + Tss->IST[Index] =3D StackTop; > + StackTop -=3D StackSwitchData->StackSize; > + > + // > + // Set the IST field to enable corresponding IST > + // > + IdtTable[StackSwitchData->Exceptions[Index]].Bits.Reserved_0 =3D > (UINT8)(Index + 1); > + } > + > + // > + // Publish GDT > + // > + AsmWriteGdtr (&Gdtr); > + > + // > + // Load current task > + // > + AsmWriteTr ((UINT16)((UINTN)StackSwitchData->TssDesc - Gdtr.Base)); > + > + // > + // Publish IDT > + // > + AsmWriteIdtr (&Idtr); > + > + return EFI_SUCCESS; > +} > + > /** > Display CPU information. >=20 > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h > index 906480134a..c88be46286 100644 > --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h > +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h > @@ -43,4 +43,7 @@ typedef struct { > UINT8 HookAfterStubHeaderCode[HOOKAFTER_STUB_SIZE]; > } RESERVED_VECTORS_DATA; >=20 > +#define CPU_TSS_DESC_SIZE sizeof (IA32_TSS_DESCRIPTOR) > +#define CPU_TSS_SIZE sizeof (IA32_TASK_STATE_SEGMENT) > + > #endif > -- > 2.14.1.windows.1