Home | History | Annotate | Download | only in X64
      1 /** @file
      2   SMM CPU misc functions for x64 arch specific.
      3 
      4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "PiSmmCpuDxeSmm.h"
     16 
     17 /**
     18   Initialize Gdt for all processors.
     19 
     20   @param[in]   Cr3          CR3 value.
     21   @param[out]  GdtStepSize  The step size for GDT table.
     22 
     23   @return GdtBase for processor 0.
     24           GdtBase for processor X is: GdtBase + (GdtStepSize * X)
     25 **/
     26 VOID *
     27 InitGdt (
     28   IN  UINTN  Cr3,
     29   OUT UINTN  *GdtStepSize
     30   )
     31 {
     32   UINTN                     Index;
     33   IA32_SEGMENT_DESCRIPTOR   *GdtDescriptor;
     34   UINTN                     TssBase;
     35   UINTN                     GdtTssTableSize;
     36   UINT8                     *GdtTssTables;
     37   UINTN                     GdtTableStepSize;
     38 
     39   //
     40   // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
     41   // on each SMI entry.
     42   //
     43   GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned
     44   GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
     45   ASSERT (GdtTssTables != NULL);
     46   GdtTableStepSize = GdtTssTableSize;
     47 
     48   for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
     49     CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE);
     50 
     51     //
     52     // Fixup TSS descriptors
     53     //
     54     TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
     55     GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
     56     GdtDescriptor->Bits.BaseLow = (UINT16)(UINTN)TssBase;
     57     GdtDescriptor->Bits.BaseMid = (UINT8)((UINTN)TssBase >> 16);
     58     GdtDescriptor->Bits.BaseHigh = (UINT8)((UINTN)TssBase >> 24);
     59 
     60     if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
     61       //
     62       // Setup top of known good stack as IST1 for each processor.
     63       //
     64       *(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize);
     65     }
     66   }
     67 
     68   *GdtStepSize = GdtTableStepSize;
     69   return GdtTssTables;
     70 }
     71