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 *
InitGdt(IN UINTN Cr3,OUT UINTN * GdtStepSize)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