1) No impact at all.

2)
    Page at stack base will be disabled.
    If Arch == IA32,
        The stack switch for handler of #PF/#DD will be setup for BSP and AP
    Else
        The handler of #PF/#DD keeps the same
    EndIf

    If StackOverFlow,
        If Arch == IA32,
            #PF is triggered and its handler is called with KnownGoodStack.
            CPU context is dumped successfully.
        Else
            #PF handler is triggered but its handler is called with corrupted 
stack.
            CPU context cannot be dumped.
        EndIf
    EndIf

3) 
    If Cpu == BSP,
        Only Exceptions will be handled. Interrupts will not.
    Else,
        No exceptions and interrupts will be handled.
    EndIf

4) 
    Page at stack base will be disabled.
    If Cpu == BSP,
        Only Exceptions will be handled. Interrupts will not.

        If Arch == IA32,
            The stack switch for handler of #PF/#DD will be setup for BSP
        Else
            The handler of #PF/#DD keeps the same
        EndIf

        If StackOverFlow,
            If Arch == IA32,
                #PF is triggered and its handler is called with KnownGoodStack.
                CPU context is dumped successfully.
            Else
                #PF handler is triggered but its handler is called with 
corrupted stack.
                CPU context cannot be dumped.
            EndIf
        EndIf
    Else,
        No exceptions and interrupts will be handled.
    EndIf

> -----Original Message-----
> From: Yao, Jiewen
> Sent: Thursday, November 23, 2017 2:25 PM
> To: Wang, Jian J <jian.j.w...@intel.com>; edk2-devel@lists.01.org
> Cc: Kinney, Michael D <michael.d.kin...@intel.com>; Dong, Eric
> <eric.d...@intel.com>; Zeng, Star <star.z...@intel.com>
> Subject: RE: [PATCH v2 7/8] UefiCpuPkg/CpuExceptionHandlerLib: Add stack
> switch support
> 
> I am ok to keep FALSE by default. But I still suggest we test existing UEFI OS
> behavior.
> 
> Please help me understand below condition, if we do not change a platform
> specific CPU driver:
> 1) If PcdCpuStackGuard is FALSE, and CPU driver is still consuming existing 
> API in
> ExceptionLib. Is there any impact?
> 2) If PcdCpuStackGuard is TRUE, and CPU driver is still consuming existing 
> API in
> ExceptionLib. Is there any impact?
> 3) If PcdCpuStackGuard is FALSE, and CPU driver is not consuming existing API 
> in
> ExceptionLib. Is there any impact?
> 4) If PcdCpuStackGuard is TRUE, and CPU driver is not consuming existing API 
> in
> ExceptionLib. Is there any impact?
> 
> 
> Thank you
> Yao Jiewen
> 
> > -----Original Message-----
> > From: Wang, Jian J
> > Sent: Thursday, November 23, 2017 2:09 PM
> > To: Yao, Jiewen <jiewen....@intel.com>; edk2-devel@lists.01.org
> > Cc: Kinney, Michael D <michael.d.kin...@intel.com>; Dong, Eric
> > <eric.d...@intel.com>; Zeng, Star <star.z...@intel.com>
> > Subject: RE: [PATCH v2 7/8] UefiCpuPkg/CpuExceptionHandlerLib: Add stack
> > switch support
> >
> > If PcdCpuStackGuard is not enabled, there's no impact. If it's enabled, the 
> > only
> > issue is that the exception dump cannot be done but no other impact. From
> this
> > point of view, maybe PcdCpuStackGuard should be FALSE by default.
> >
> > > -----Original Message-----
> > > From: Yao, Jiewen
> > > Sent: Thursday, November 23, 2017 1:59 PM
> > > To: Yao, Jiewen <jiewen....@intel.com>; Wang, Jian J
> > <jian.j.w...@intel.com>;
> > > edk2-devel@lists.01.org
> > > Cc: Kinney, Michael D <michael.d.kin...@intel.com>; Dong, Eric
> > > <eric.d...@intel.com>; Zeng, Star <star.z...@intel.com>
> > > Subject: RE: [PATCH v2 7/8] UefiCpuPkg/CpuExceptionHandlerLib: Add stack
> > > switch support
> > >
> > > One more question:
> > > I notice not all platforms are using the CpuDxe in UefiCpuPkg.
> > > If so, is there any impact to the platform whose CPU driver does not have
> such
> > > InitializeCpuExceptionStackSwitchHandlers() call?
> > > Have you tested that condition?
> > >
> > > Thank you
> > > Yao Jiewen
> > >
> > > > -----Original Message-----
> > > > From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf Of
> > Yao,
> > > > Jiewen
> > > > Sent: Thursday, November 23, 2017 1:50 PM
> > > > To: Wang, Jian J <jian.j.w...@intel.com>; edk2-devel@lists.01.org
> > > > Cc: Kinney, Michael D <michael.d.kin...@intel.com>; Dong, Eric
> > > > <eric.d...@intel.com>; Zeng, Star <star.z...@intel.com>
> > > > Subject: Re: [edk2] [PATCH v2 7/8] UefiCpuPkg/CpuExceptionHandlerLib:
> Add
> > > > stack switch support
> > > >
> > > > 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 <star.z...@intel.com>; Dong, Eric 
> > > > > <eric.d...@intel.com>;
> > > Yao,
> > > > > Jiewen <jiewen....@intel.com>; Kinney, Michael D
> > > > > <michael.d.kin...@intel.com>
> > > > > Subject: [PATCH v2 7/8] UefiCpuPkg/CpuExceptionHandlerLib: Add stack
> > > switch
> > > > > support
> > > > >
> > > > > > 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 
> > > > > > early
> > > > > >       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.
> > > > >
> > > > > If Stack Guard is enabled and there's really a stack overflow happened
> > during
> > > > > 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
> > driver,
> > > > > cannot be executed and cannot dump the processor information.
> > > > >
> > > > > Without those information, it's very difficult for the BIOS developers
> locate
> > > > > the root cause of stack overflow. And without a workable stack, the
> > > developer
> > > > > cannot event use single step to debug the UEFI driver with JTAG 
> > > > > debugger.
> > > > >
> > > > > In order to make sure the exception handler to execute normally after
> stack
> > > > > overflow. We need separate stacks for exception handlers in case of
> > > unusable
> > > > > stack.
> > > > >
> > > > > IA processor allows to switch to a new stack during handling interrupt
> and
> > > > > exception. But X64 and IA32 provides different ways to make it. X64
> > provides
> > > > > interrupt stack table (IST) to allow maximum 7 different exceptions to
> have
> > > > > new stack for its handler. IA32 doesn't have IST mechanism and can 
> > > > > only
> use
> > > > > task gate to do it since task switch allows to load a new stack 
> > > > > through its
> > > > > task-state segment (TSS).
> > > > >
> > > > > Cc: Star Zeng <star.z...@intel.com>
> > > > > Cc: Eric Dong <eric.d...@intel.com>
> > > > > Cc: Jiewen Yao <jiewen....@intel.com>
> > > > > Cc: Michael Kinney <michael.d.kin...@intel.com>
> > > > > Suggested-by: Ayellet Wolman <ayellet.wol...@intel.com>
> > > > > Contributed-under: TianoCore Contribution Agreement 1.1
> > > > > Signed-off-by: Jian J Wang <jian.j.w...@intel.com>
> > > > > ---
> > > > >  .../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
> > > > >
> > > > > 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,
> > 0x2c,
> > > > 0x83 }
> > > > > \
> > > > >    }
> > > > >
> > > > > +#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
> > > > >    );
> > > > >
> > > > > +/**
> > > > > +  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
> > > > >
> > > > > 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
> > > > >
> > > > > +[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
> > > > =
> > > > > 0;
> > > > >
> > > > >  EXCEPTION_HANDLER_DATA      mExceptionHandlerData;
> > > > >
> > > > > +UINT8
> > > > > mNewStack[CPU_STACK_SWITCH_EXCEPTION_NUMBER *
> > > > > +
> > > > CPU_KNOWN_GOOD_STACK_SIZE]
> > > > > = {0};
> > > > > +UINT8                       mNewGdt[CPU_TSS_GDT_SIZE] = {0};
> > > > > +
> > > > >  /**
> > > > >    Common exception handler.
> > > > >
> > > > > @@ -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          =
> > > > > mReservedVectorsData;
> > > > >    mExceptionHandlerData.ExternalInterruptHandler =
> > > > > mExternalInterruptHandlerTable;
> > > > >    InitializeSpinLock (&mExceptionHandlerData.DisplayMessageSpinLock);
> > > > > -  return InitializeCpuExceptionHandlersWorker (VectorInfo,
> > > > > &mExceptionHandlerData);
> > > > > +  Status = InitializeCpuExceptionHandlersWorker (VectorInfo,
> > > > > &mExceptionHandlerData);
> > > > > +  if (!EFI_ERROR (Status) && PcdGetBool (PcdCpuStackGuard)) {
> > > > > +    AsmReadIdtr (&Idtr);
> > > > > +    AsmReadGdtr (&Gdtr);
> > > > > +
> > > > > +    StackSwitchData.StackTop = (UINTN)mNewStack;
> > > > > +    StackSwitchData.StackSize = CPU_KNOWN_GOOD_STACK_SIZE;
> > > > > +    StackSwitchData.Exceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;
> > > > > +    StackSwitchData.ExceptionNumber =
> > > > > CPU_STACK_SWITCH_EXCEPTION_NUMBER;
> > > > > +    StackSwitchData.IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)Idtr.Base;
> > > > > +    StackSwitchData.GdtTable = (IA32_SEGMENT_DESCRIPTOR
> > *)mNewGdt;
> > > > > +    StackSwitchData.GdtSize = sizeof (mNewGdt);
> > > > > +    StackSwitchData.TssDesc = (IA32_TSS_DESCRIPTOR *)(mNewGdt +
> > > > > Gdtr.Limit + 1);
> > > > > +    StackSwitchData.Tss = (IA32_TASK_STATE_SEGMENT *)(mNewGdt +
> > > > > Gdtr.Limit + 1 +
> > > > > +
> > > > > CPU_TSS_DESC_SIZE);
> > > > > +    Status = InitializeCpuExceptionStackSwitchHandlers (
> > > > > +               &StackSwitchData
> > > > > +               );
> > > > > +  }
> > > > > +  return Status;
> > > > >  }
> > > > >
> > > > >  /**
> > > > > @@ -197,3 +225,26 @@ RegisterCpuInterruptHandler (
> > > > >  {
> > > > >    return RegisterCpuInterruptHandlerWorker (InterruptType,
> > > > InterruptHandler,
> > > > > &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 =
> > > > > ReservedVectors[ExceptionType].ExceptionData;
> > > > >  }
> > > > >
> > > > > +/**
> > > > > +  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                             Vector;
> > > > > +  UINTN                             TssBase;
> > > > > +  UINTN                             GdtSize;
> > > > > +  EXCEPTION_HANDLER_TEMPLATE_MAP    TemplateMap;
> > > > > +
> > > > > +  if (StackSwitchData == NULL ||
> > > > > +      StackSwitchData->StackTop == 0 ||
> > > > > +      StackSwitchData->StackSize == 0 ||
> > > > > +      StackSwitchData->Exceptions == NULL ||
> > > > > +      StackSwitchData->ExceptionNumber == 0 ||
> > > > > +      StackSwitchData->GdtTable == NULL ||
> > > > > +      StackSwitchData->IdtTable == NULL ||
> > > > > +      StackSwitchData->TssDesc == NULL ||
> > > > > +      StackSwitchData->Tss == NULL) {
> > > > > +    return EFI_INVALID_PARAMETER;
> > > > > +  }
> > > > > +
> > > > > +  //
> > > > > +  // The caller is responsible for that the GDT table, no matter the
> existing
> > > > > +  // one or newly allocated, has enough space to hold descriptors for
> > > > exception
> > > > > +  // task-state segments.
> > > > > +  //
> > > > > +  if (((UINTN)StackSwitchData->GdtTable & (IA32_GDT_ALIGNMENT -
> > 1)) !=
> > > 0)
> > > > {
> > > > > +    return EFI_INVALID_PARAMETER;
> > > > > +  }
> > > > > +
> > > > > +  if ((UINTN)StackSwitchData->TssDesc <
> > > > (UINTN)(StackSwitchData->GdtTable))
> > > > > {
> > > > > +    return EFI_INVALID_PARAMETER;
> > > > > +  }
> > > > > +
> > > > > +  if ((UINTN)StackSwitchData->TssDesc >=
> > > > > +          ((UINTN)(StackSwitchData->GdtTable) +
> > > > StackSwitchData->GdtSize))
> > > > > {
> > > > > +    return EFI_INVALID_PARAMETER;
> > > > > +  }
> > > > > +
> > > > > +  GdtSize = (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 != Gdtr.Base) {
> > > > > +    CopyMem (StackSwitchData->GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit
> > +
> > > > 1);
> > > > > +    Gdtr.Base = (UINTN)StackSwitchData->GdtTable;
> > > > > +    Gdtr.Limit = (UINT16)StackSwitchData->GdtSize - 1;
> > > > > +  }
> > > > > +
> > > > > +  if ((UINTN)StackSwitchData->IdtTable != Idtr.Base) {
> > > > > +    Idtr.Base = (UINTN)StackSwitchData->IdtTable;
> > > > > +  }
> > > > > +
> > > > > +  //
> > > > > +  // Fixup current task descriptor. Task-state segment for current 
> > > > > task
> will
> > > > > +  // be filled by processor during task switching.
> > > > > +  //
> > > > > +  TssDesc = StackSwitchData->TssDesc;
> > > > > +  Tss     = StackSwitchData->Tss;
> > > > > +
> > > > > +  TssBase = (UINTN)Tss;
> > > > > +  TssDesc->Bits.LimitLow   = sizeof(IA32_TASK_STATE_SEGMENT) - 1;
> > > > > +  TssDesc->Bits.BaseLow    = (UINT16)TssBase;
> > > > > +  TssDesc->Bits.BaseMid    = (UINT8)(TssBase >> 16);
> > > > > +  TssDesc->Bits.Type       = IA32_GDT_TYPE_TSS;
> > > > > +  TssDesc->Bits.P          = 1;
> > > > > +  TssDesc->Bits.LimitHigh  = 0;
> > > > > +  TssDesc->Bits.BaseHigh   = (UINT8)(TssBase >> 24);
> > > > > +
> > > > > +  //
> > > > > +  // Fixup exception task descriptor and task-state segment
> > > > > +  //
> > > > > +  AsmGetTssTemplateMap (&TemplateMap);
> > > > > +  StackTop = StackSwitchData->StackTop - CPU_STACK_ALIGNMENT;
> > > > > +  StackTop = (UINTN)ALIGN_POINTER (StackTop,
> > CPU_STACK_ALIGNMENT);
> > > > > +  IdtTable = StackSwitchData->IdtTable;
> > > > > +  for (Index = 0; Index < StackSwitchData->ExceptionNumber; ++Index) 
> > > > > {
> > > > > +    TssDesc += 1;
> > > > > +    Tss     += 1;
> > > > > +
> > > > > +    //
> > > > > +    // Fixup TSS descriptor
> > > > > +    //
> > > > > +    TssBase = (UINTN)Tss;
> > > > > +
> > > > > +    TssDesc->Bits.LimitLow  = sizeof(IA32_TASK_STATE_SEGMENT) - 1;
> > > > > +    TssDesc->Bits.BaseLow   = (UINT16)TssBase;
> > > > > +    TssDesc->Bits.BaseMid   = (UINT8)(TssBase >> 16);
> > > > > +    TssDesc->Bits.Type      = IA32_GDT_TYPE_TSS;
> > > > > +    TssDesc->Bits.P         = 1;
> > > > > +    TssDesc->Bits.LimitHigh = 0;
> > > > > +    TssDesc->Bits.BaseHigh  = (UINT8)(TssBase >> 24);
> > > > > +
> > > > > +    //
> > > > > +    // Fixup TSS
> > > > > +    //
> > > > > +    Vector = StackSwitchData->Exceptions[Index];
> > > > > +    Tss->EIP    = (UINT32)(TemplateMap.ExceptionStart
> > > > > +                           + Vector *
> > > > > TemplateMap.ExceptionStubHeaderSize);
> > > > > +    Tss->EFLAGS = 0x2;
> > > > > +    Tss->ESP    = StackTop;
> > > > > +    Tss->CR3    = AsmReadCr3 ();
> > > > > +    Tss->ES     = AsmReadEs ();
> > > > > +    Tss->CS     = AsmReadCs ();
> > > > > +    Tss->SS     = AsmReadSs ();
> > > > > +    Tss->DS     = AsmReadDs ();
> > > > > +    Tss->FS     = AsmReadFs ();
> > > > > +    Tss->GS     = AsmReadGs ();
> > > > > +
> > > > > +    StackTop   -= StackSwitchData->StackSize;
> > > > > +
> > > > > +    //
> > > > > +    // Update IDT to use Task Gate for given exception
> > > > > +    //
> > > > > +    IdtTable[Vector].Bits.OffsetLow  = 0;
> > > > > +    IdtTable[Vector].Bits.Selector   = (UINT16)((UINTN)TssDesc -
> > Gdtr.Base);
> > > > > +    IdtTable[Vector].Bits.Reserved_0 = 0;
> > > > > +    IdtTable[Vector].Bits.GateType   = IA32_IDT_GATE_TYPE_TASK;
> > > > > +    IdtTable[Vector].Bits.OffsetHigh = 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.
> > > > >
> > > > > 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;
> > > > >
> > > > > +#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.<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
> > > > > +; 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 = 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 = 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 
> > > > > EFLAGs
> 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
> > stack
> > > > > +    movzx  ebx, word [ecx + IA32_TSS._CS]
> > > > > +    mov    [eax - 0x8], ebx                      ; create CS in old
> > stack
> > > > > +    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 -
> > > > AsmExceptionEntryBegin)
> > > > > / 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 =
> > > > > ReservedVectors[ExceptionType].ExceptionData;
> > > > >  }
> > > > >
> > > > > +/**
> > > > > +  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 == NULL ||
> > > > > +      StackSwitchData->StackTop == 0 ||
> > > > > +      StackSwitchData->StackSize == 0 ||
> > > > > +      StackSwitchData->Exceptions == NULL ||
> > > > > +      StackSwitchData->ExceptionNumber == 0 ||
> > > > > +      StackSwitchData->GdtTable == NULL ||
> > > > > +      StackSwitchData->IdtTable == NULL ||
> > > > > +      StackSwitchData->TssDesc == NULL ||
> > > > > +      StackSwitchData->Tss == NULL) {
> > > > > +    return EFI_INVALID_PARAMETER;
> > > > > +  }
> > > > > +
> > > > > +  //
> > > > > +  // The caller is responsible for that the GDT table, no matter the
> existing
> > > > > +  // one or newly allocated, has enough space to hold descriptors for
> > > > exception
> > > > > +  // task-state segments.
> > > > > +  //
> > > > > +  if (((UINTN)StackSwitchData->GdtTable & (IA32_GDT_ALIGNMENT -
> > 1)) !=
> > > 0)
> > > > {
> > > > > +    return EFI_INVALID_PARAMETER;
> > > > > +  }
> > > > > +
> > > > > +  if ((UINTN)StackSwitchData->TssDesc <
> > > > (UINTN)(StackSwitchData->GdtTable))
> > > > > {
> > > > > +    return EFI_INVALID_PARAMETER;
> > > > > +  }
> > > > > +
> > > > > +  if ((UINTN)StackSwitchData->TssDesc >=
> > > > > +          ((UINTN)(StackSwitchData->GdtTable) +
> > > > StackSwitchData->GdtSize))
> > > > > {
> > > > > +    return EFI_INVALID_PARAMETER;
> > > > > +  }
> > > > > +
> > > > > +  GdtSize = (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 != Gdtr.Base) {
> > > > > +    CopyMem (StackSwitchData->GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit
> > +
> > > > 1);
> > > > > +    Gdtr.Base = (UINTN)StackSwitchData->GdtTable;
> > > > > +    Gdtr.Limit = (UINT16)GdtSize - 1;
> > > > > +  }
> > > > > +
> > > > > +  if ((UINTN)StackSwitchData->IdtTable != Idtr.Base) {
> > > > > +    Idtr.Base = (UINTN)StackSwitchData->IdtTable;
> > > > > +  }
> > > > > +
> > > > > +  //
> > > > > +  // Fixup current task descriptor. Task-state segment for current 
> > > > > task
> will
> > > > > +  // be filled by processor during task switching.
> > > > > +  //
> > > > > +  TssDesc = StackSwitchData->TssDesc;
> > > > > +  Tss     = StackSwitchData->Tss;
> > > > > +
> > > > > +  TssBase = (UINTN)Tss;
> > > > > +  TssDesc->Bits.LimitLow   = sizeof(IA32_TASK_STATE_SEGMENT) - 1;
> > > > > +  TssDesc->Bits.BaseLow    = (UINT16)TssBase;
> > > > > +  TssDesc->Bits.BaseMidl   = (UINT8)(TssBase >> 16);
> > > > > +  TssDesc->Bits.Type       = IA32_GDT_TYPE_TSS;
> > > > > +  TssDesc->Bits.P          = 1;
> > > > > +  TssDesc->Bits.LimitHigh  = 0;
> > > > > +  TssDesc->Bits.BaseMidh   = (UINT8)(TssBase >> 24);
> > > > > +  TssDesc->Bits.BaseHigh   = (UINT32)(TssBase >> 32);
> > > > > +
> > > > > +  //
> > > > > +  // Fixup exception task descriptor and task-state segment
> > > > > +  //
> > > > > +  StackTop = StackSwitchData->StackTop - CPU_STACK_ALIGNMENT;
> > > > > +  StackTop = (UINTN)ALIGN_POINTER (StackTop,
> > CPU_STACK_ALIGNMENT);
> > > > > +  IdtTable = StackSwitchData->IdtTable;
> > > > > +  for (Index = 0; Index < StackSwitchData->ExceptionNumber; ++Index) 
> > > > > {
> > > > > +    //
> > > > > +    // Fixup IST
> > > > > +    //
> > > > > +    Tss->IST[Index] = StackTop;
> > > > > +    StackTop -= StackSwitchData->StackSize;
> > > > > +
> > > > > +    //
> > > > > +    // Set the IST field to enable corresponding IST
> > > > > +    //
> > > > > +    IdtTable[StackSwitchData->Exceptions[Index]].Bits.Reserved_0 =
> > > > > (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.
> > > > >
> > > > > 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;
> > > > >
> > > > > +#define CPU_TSS_DESC_SIZE sizeof (IA32_TSS_DESCRIPTOR)
> > > > > +#define CPU_TSS_SIZE      sizeof (IA32_TASK_STATE_SEGMENT)
> > > > > +
> > > > >  #endif
> > > > > --
> > > > > 2.14.1.windows.1
> > > >
> > > > _______________________________________________
> > > > edk2-devel mailing list
> > > > edk2-devel@lists.01.org
> > > > https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to