]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg/PiSmmCpuDxeSmm: Add paging protection.
authorJiewen Yao <jiewen.yao@intel.com>
Sun, 23 Oct 2016 15:19:52 +0000 (23:19 +0800)
committerJiewen Yao <jiewen.yao@intel.com>
Thu, 17 Nov 2016 08:30:07 +0000 (16:30 +0800)
PiSmmCpuDxeSmm consumes SmmAttributesTable and setup page table:
1) Code region is marked as read-only and Data region is non-executable,
if the PE image is 4K aligned.
2) Important data structure is set to RO, such as GDT/IDT.
3) SmmSaveState is set to non-executable,
and SmmEntrypoint is set to read-only.
4) If static page is supported, page table is read-only.

We use page table to protect other components, and itself.

If we use dynamic paging, we can still provide *partial* protection.
And hope page table is not modified by other components.

The XD enabling code is moved to SmiEntry to let NX take effect.

Cc: Jeff Fan <jeff.fan@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
25 files changed:
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c
UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c [new file with mode: 0644]
UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h
UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.S
UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.asm
UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.nasm
UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.S
UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.asm
UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.nasm
UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.c

index a871bef4e28f9c32202a32d5ea1e675cc08a6984..65f09e562228542063afdde8bc44171f12e45782 100644 (file)
@@ -58,7 +58,7 @@ SmmInitPageTable (
   if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
     InitializeIDTSmmStackGuard ();\r
   }\r
-  return Gen4GPageTable (0, TRUE);\r
+  return Gen4GPageTable (TRUE);\r
 }\r
 \r
 /**\r
@@ -99,7 +99,7 @@ SmiPFHandler (
   if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&\r
       (PFAddress >= mCpuHotPlugData.SmrrBase) &&\r
       (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {\r
-    DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));\r
+    DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));\r
     CpuDeadLoop ();\r
   }\r
 \r
@@ -109,7 +109,7 @@ SmiPFHandler (
   if ((PFAddress < mCpuHotPlugData.SmrrBase) ||\r
       (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
     if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
-      DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));\r
+      DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));\r
       DEBUG_CODE (\r
         DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
       );\r
@@ -128,3 +128,68 @@ SmiPFHandler (
 \r
   ReleaseSpinLock (mPFLock);\r
 }\r
+\r
+/**\r
+  This function sets memory attribute for page table.\r
+**/\r
+VOID\r
+SetPageTableAttributes (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                 Index2;\r
+  UINTN                 Index3;\r
+  UINT64                *L1PageTable;\r
+  UINT64                *L2PageTable;\r
+  UINT64                *L3PageTable;\r
+  BOOLEAN               IsSplitted;\r
+  BOOLEAN               PageTableSplitted;\r
+\r
+  DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));\r
+\r
+  //\r
+  // Disable write protection, because we need mark page table to be write protected.\r
+  // We need *write* page table memory, to mark itself to be *read only*.\r
+  //\r
+  AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);\r
+\r
+  do {\r
+    DEBUG ((DEBUG_INFO, "Start...\n"));\r
+    PageTableSplitted = FALSE;\r
+\r
+    L3PageTable = (UINT64 *)GetPageTableBase ();\r
+\r
+    SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+    PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+\r
+    for (Index3 = 0; Index3 < 4; Index3++) {\r
+      L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);\r
+      if (L2PageTable == NULL) {\r
+        continue;\r
+      }\r
+\r
+      SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+      PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+\r
+      for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {\r
+        if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
+          // 2M\r
+          continue;\r
+        }\r
+        L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);\r
+        if (L1PageTable == NULL) {\r
+          continue;\r
+        }\r
+        SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+        PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+      }\r
+    }\r
+  } while (PageTableSplitted);\r
+\r
+  //\r
+  // Enable write protection, after page table updated.\r
+  //\r
+  AsmWriteCr0 (AsmReadCr0() | CR0_WP);\r
+\r
+  return ;\r
+}\r
index ec5b9a0b04231affd66d7a04c661625199048343..0c075582c3856cb107ec205fa5c978b43bb70085 100644 (file)
@@ -1,6 +1,6 @@
 #------------------------------------------------------------------------------\r
 #\r
-# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 # This program and the accompanying materials\r
 # are licensed and made available under the terms and conditions of the BSD License\r
 # which accompanies this distribution.  The full text of the license may be found at\r
@@ -24,9 +24,13 @@ ASM_GLOBAL  ASM_PFX(gcSmiHandlerSize)
 ASM_GLOBAL  ASM_PFX(gSmiCr3)\r
 ASM_GLOBAL  ASM_PFX(gSmiStack)\r
 ASM_GLOBAL  ASM_PFX(gSmbase)\r
+ASM_GLOBAL  ASM_PFX(mXdSupported)\r
 ASM_GLOBAL  ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))\r
 ASM_GLOBAL  ASM_PFX(gSmiHandlerIdtr)\r
 \r
+.equ            MSR_EFER, 0xc0000080\r
+.equ            MSR_EFER_XD, 0x800\r
+\r
 .equ            DSC_OFFSET, 0xfb00\r
 .equ            DSC_GDTPTR, 0x30\r
 .equ            DSC_GDTSIZ, 0x38\r
@@ -122,8 +126,41 @@ L11:
     orl     $BIT10, %eax\r
 L12:                                       # as cr4.PGE is not set here, refresh cr3\r
     movl    %eax, %cr4                     # in PreModifyMtrrs() to flush TLB.\r
+\r
+    cmpb    $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))\r
+    jz      L5\r
+# Load TSS\r
+    movb    $0x89, (TSS_SEGMENT + 5)(%ebp) # clear busy flag\r
+    movl    $TSS_SEGMENT, %eax\r
+    ltrw    %ax\r
+L5:\r
+\r
+# enable NXE if supported\r
+    .byte   0xb0                           # mov al, imm8\r
+ASM_PFX(mXdSupported): .byte 1\r
+    cmpb    $0, %al\r
+    jz      SkipNxe\r
+#\r
+# Check XD disable bit\r
+#\r
+    movl    $MSR_IA32_MISC_ENABLE, %ecx\r
+    rdmsr\r
+    pushl   %edx                           # save MSR_IA32_MISC_ENABLE[63-32]\r
+    testl   $BIT2, %edx                    # MSR_IA32_MISC_ENABLE[34]\r
+    jz      L13\r
+    andw    $0x0FFFB, %dx                  # clear XD Disable bit if it is set\r
+    wrmsr\r
+L13:\r
+    movl    $MSR_EFER, %ecx\r
+    rdmsr\r
+    orw     $MSR_EFER_XD,%ax               # enable NXE\r
+    wrmsr\r
+SkipNxe:\r
+    subl    $4, %esp\r
+NxeDone:\r
+\r
     movl    %cr0, %ebx\r
-    orl     $0x080010000, %ebx             # enable paging + WP\r
+    orl     $0x080010023, %ebx             # enable paging + WP + NE + MP + PE\r
     movl    %ebx, %cr0\r
     leal    DSC_OFFSET(%edi),%ebx\r
     movw    DSC_DS(%ebx),%ax\r
@@ -135,35 +172,39 @@ L12:                                       # as cr4.PGE is not set here, refresh
     movw    DSC_SS(%ebx),%ax\r
     movl    %eax, %ss\r
 \r
-    cmpb    $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))\r
-    jz      L5\r
-\r
-# Load TSS\r
-    movb    $0x89, (TSS_SEGMENT + 5)(%ebp) # clear busy flag\r
-    movl    $TSS_SEGMENT, %eax\r
-    ltrw    %ax\r
-L5:\r
-\r
 #   jmp     _SmiHandler                 # instruction is not needed\r
 \r
 _SmiHandler:\r
-    movl    (%esp), %ebx\r
+    movl    4(%esp), %ebx\r
 \r
     pushl   %ebx\r
     movl    $ASM_PFX(CpuSmmDebugEntry), %eax\r
     call    *%eax\r
-    popl    %ecx\r
-    \r
+    addl    $4, %esp\r
+\r
     pushl   %ebx\r
     movl    $ASM_PFX(SmiRendezvous), %eax\r
     call    *%eax\r
-    popl    %ecx\r
+    addl    $4, %esp\r
 \r
     pushl   %ebx\r
     movl    $ASM_PFX(CpuSmmDebugExit), %eax\r
     call    *%eax\r
-    popl    %ecx\r
-\r
+    addl    $4, %esp\r
+\r
+    movl    $ASM_PFX(mXdSupported), %eax\r
+    movb    (%eax), %al\r
+    cmpb    $0, %al\r
+    jz      L16\r
+    popl    %edx                        # get saved MSR_IA32_MISC_ENABLE[63-32]\r
+    testl   $BIT2, %edx\r
+    jz      L16\r
+    movl    $MSR_IA32_MISC_ENABLE, %ecx\r
+    rdmsr\r
+    orw     $BIT2, %dx                  # set XD Disable bit if it was set before entering into SMM\r
+    wrmsr\r
+\r
+L16:\r
     rsm\r
 \r
 ASM_PFX(gcSmiHandlerSize):    .word      . - _SmiEntryPoint\r
index ac1a9b48ddd0d89569a10417b3753bdf9725c5f2..eda1708e3f3a9fc76ee4d4bcac004bbf5ead5ebd 100644 (file)
@@ -1,5 +1,5 @@
 ;------------------------------------------------------------------------------ ;\r
-; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 ; This program and the accompanying materials\r
 ; are licensed and made available under the terms and conditions of the BSD License\r
 ; which accompanies this distribution.  The full text of the license may be found at\r
     .model  flat,C\r
     .xmm\r
 \r
+MSR_IA32_MISC_ENABLE  EQU     1A0h\r
+MSR_EFER      EQU     0c0000080h\r
+MSR_EFER_XD   EQU     0800h\r
+\r
 DSC_OFFSET    EQU     0fb00h\r
 DSC_GDTPTR    EQU     30h\r
 DSC_GDTSIZ    EQU     38h\r
@@ -43,6 +47,7 @@ EXTERNDEF   gcSmiHandlerSize:WORD
 EXTERNDEF   gSmiCr3:DWORD\r
 EXTERNDEF   gSmiStack:DWORD\r
 EXTERNDEF   gSmbase:DWORD\r
+EXTERNDEF   mXdSupported:BYTE\r
 EXTERNDEF   FeaturePcdGet (PcdCpuSmmStackGuard):BYTE\r
 EXTERNDEF   gSmiHandlerIdtr:FWORD\r
 \r
@@ -128,8 +133,42 @@ gSmiCr3     DD      ?
     or      eax, BIT10\r
 @@:                                     ; as cr4.PGE is not set here, refresh cr3\r
     mov     cr4, eax                    ; in PreModifyMtrrs() to flush TLB.\r
+\r
+    cmp     FeaturePcdGet (PcdCpuSmmStackGuard), 0\r
+    jz      @F\r
+; Load TSS\r
+    mov     byte ptr [ebp + TSS_SEGMENT + 5], 89h ; clear busy flag\r
+    mov     eax, TSS_SEGMENT\r
+    ltr     ax\r
+@@:\r
+\r
+; enable NXE if supported\r
+    DB      0b0h                        ; mov al, imm8\r
+mXdSupported     DB      1\r
+    cmp     al, 0\r
+    jz      @SkipXd\r
+;\r
+; Check XD disable bit\r
+;\r
+    mov     ecx, MSR_IA32_MISC_ENABLE\r
+    rdmsr\r
+    push    edx                        ; save MSR_IA32_MISC_ENABLE[63-32]\r
+    test    edx, BIT2                  ; MSR_IA32_MISC_ENABLE[34]\r
+    jz      @f\r
+    and     dx, 0FFFBh                 ; clear XD Disable bit if it is set\r
+    wrmsr\r
+@@:\r
+    mov     ecx, MSR_EFER\r
+    rdmsr\r
+    or      ax, MSR_EFER_XD             ; enable NXE\r
+    wrmsr\r
+    jmp     @XdDone\r
+@SkipXd:\r
+    sub     esp, 4\r
+@XdDone:\r
+\r
     mov     ebx, cr0\r
-    or      ebx, 080010000h             ; enable paging + WP\r
+    or      ebx, 080010023h             ; enable paging + WP + NE + MP + PE\r
     mov     cr0, ebx\r
     lea     ebx, [edi + DSC_OFFSET]\r
     mov     ax, [ebx + DSC_DS]\r
@@ -141,34 +180,38 @@ gSmiCr3     DD      ?
     mov     ax, [ebx + DSC_SS]\r
     mov     ss, eax\r
 \r
-    cmp     FeaturePcdGet (PcdCpuSmmStackGuard), 0\r
-    jz      @F\r
-\r
-; Load TSS\r
-    mov     byte ptr [ebp + TSS_SEGMENT + 5], 89h ; clear busy flag\r
-    mov     eax, TSS_SEGMENT\r
-    ltr     ax\r
-@@:\r
 ;   jmp     _SmiHandler                 ; instruction is not needed\r
 \r
 _SmiHandler PROC\r
-    mov     ebx, [esp]                  ; CPU Index\r
-\r
+    mov     ebx, [esp + 4]                  ; CPU Index\r
     push    ebx\r
     mov     eax, CpuSmmDebugEntry\r
     call    eax\r
-    pop     ecx\r
+    add     esp, 4\r
 \r
     push    ebx\r
     mov     eax, SmiRendezvous\r
     call    eax\r
-    pop     ecx\r
-    \r
+    add     esp, 4\r
+\r
     push    ebx\r
     mov     eax, CpuSmmDebugExit\r
     call    eax\r
-    pop     ecx\r
+    add     esp, 4\r
 \r
+    mov     eax, mXdSupported\r
+    mov     al, [eax]\r
+    cmp     al, 0\r
+    jz      @f\r
+    pop     edx                       ; get saved MSR_IA32_MISC_ENABLE[63-32]\r
+    test    edx, BIT2\r
+    jz      @f\r
+    mov     ecx, MSR_IA32_MISC_ENABLE\r
+    rdmsr\r
+    or      dx, BIT2                  ; set XD Disable bit if it was set before entering into SMM\r
+    wrmsr\r
+\r
+@@:\r
     rsm\r
 _SmiHandler ENDP\r
 \r
index 4fb0c13508fc51480555b54c0bcb0388c265b84d..d50a3170aa8f39b8cb3ea48c8238481f8d27a262 100644 (file)
 ;\r
 ;-------------------------------------------------------------------------------\r
 \r
+%define MSR_IA32_MISC_ENABLE 0x1A0\r
+%define MSR_EFER      0xc0000080\r
+%define MSR_EFER_XD   0x800\r
+\r
 %define DSC_OFFSET 0xfb00\r
 %define DSC_GDTPTR 0x30\r
 %define DSC_GDTSIZ 0x38\r
@@ -40,6 +44,7 @@ global ASM_PFX(gcSmiHandlerSize)
 global ASM_PFX(gSmiCr3)\r
 global ASM_PFX(gSmiStack)\r
 global ASM_PFX(gSmbase)\r
+global ASM_PFX(mXdSupported)\r
 extern ASM_PFX(gSmiHandlerIdtr)\r
 \r
     SECTION .text\r
@@ -56,7 +61,7 @@ _SmiEntryPoint:
     mov     ebp, eax                      ; ebp = GDT base\r
 o32 lgdt    [cs:bx]                       ; lgdt fword ptr cs:[bx]\r
     mov     ax, PROTECT_MODE_CS\r
-    mov     [cs:bx-0x2],ax    \r
+    mov     [cs:bx-0x2],ax\r
     DB      0x66, 0xbf                   ; mov edi, SMBASE\r
 ASM_PFX(gSmbase): DD 0\r
     lea     eax, [edi + (@32bit - _SmiEntryPoint) + 0x8000]\r
@@ -66,7 +71,7 @@ ASM_PFX(gSmbase): DD 0
     or      ebx, 0x23\r
     mov     cr0, ebx\r
     jmp     dword 0x0:0x0\r
-_GdtDesc:   \r
+_GdtDesc:\r
     DW 0\r
     DD 0\r
 \r
@@ -115,8 +120,42 @@ ASM_PFX(gSmiCr3): DD 0
     or      eax, BIT10\r
 .4:                                     ; as cr4.PGE is not set here, refresh cr3\r
     mov     cr4, eax                    ; in PreModifyMtrrs() to flush TLB.\r
+\r
+    cmp     byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))], 0\r
+    jz      .6\r
+; Load TSS\r
+    mov     byte [ebp + TSS_SEGMENT + 5], 0x89 ; clear busy flag\r
+    mov     eax, TSS_SEGMENT\r
+    ltr     ax\r
+.6:\r
+\r
+; enable NXE if supported\r
+    DB      0b0h                        ; mov al, imm8\r
+ASM_PFX(mXdSupported):     DB      1\r
+    cmp     al, 0\r
+    jz      @SkipXd\r
+;\r
+; Check XD disable bit\r
+;\r
+    mov     ecx, MSR_IA32_MISC_ENABLE\r
+    rdmsr\r
+    push    edx                        ; save MSR_IA32_MISC_ENABLE[63-32]\r
+    test    edx, BIT2                  ; MSR_IA32_MISC_ENABLE[34]\r
+    jz      .5\r
+    and     dx, 0xFFFB                 ; clear XD Disable bit if it is set\r
+    wrmsr\r
+.5:\r
+    mov     ecx, MSR_EFER\r
+    rdmsr\r
+    or      ax, MSR_EFER_XD             ; enable NXE\r
+    wrmsr\r
+    jmp     @XdDone\r
+@SkipXd:\r
+    sub     esp, 4\r
+@XdDone:\r
+\r
     mov     ebx, cr0\r
-    or      ebx, 0x080010000            ; enable paging + WP\r
+    or      ebx, 0x80010023             ; enable paging + WP + NE + MP + PE\r
     mov     cr0, ebx\r
     lea     ebx, [edi + DSC_OFFSET]\r
     mov     ax, [ebx + DSC_DS]\r
@@ -128,35 +167,39 @@ ASM_PFX(gSmiCr3): DD 0
     mov     ax, [ebx + DSC_SS]\r
     mov     ss, eax\r
 \r
-    cmp     byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))], 0\r
-    jz      .5\r
-\r
-; Load TSS\r
-    mov     byte [ebp + TSS_SEGMENT + 5], 0x89 ; clear busy flag\r
-    mov     eax, TSS_SEGMENT\r
-    ltr     ax\r
-.5:\r
 ;   jmp     _SmiHandler                 ; instruction is not needed\r
 \r
 global ASM_PFX(SmiHandler)\r
 ASM_PFX(SmiHandler):\r
-    mov     ebx, [esp]                  ; CPU Index\r
-\r
+    mov     ebx, [esp + 4]                  ; CPU Index\r
     push    ebx\r
     mov     eax, ASM_PFX(CpuSmmDebugEntry)\r
     call    eax\r
-    pop     ecx\r
+    add     esp, 4\r
 \r
     push    ebx\r
     mov     eax, ASM_PFX(SmiRendezvous)\r
     call    eax\r
-    pop     ecx\r
-    \r
+    add     esp, 4\r
+\r
     push    ebx\r
     mov     eax, ASM_PFX(CpuSmmDebugExit)\r
     call    eax\r
-    pop     ecx\r
-\r
+    add     esp, 4\r
+\r
+    mov     eax, ASM_PFX(mXdSupported)\r
+    mov     al, [eax]\r
+    cmp     al, 0\r
+    jz      .7\r
+    pop     edx                       ; get saved MSR_IA32_MISC_ENABLE[63-32]\r
+    test    edx, BIT2\r
+    jz      .7\r
+    mov     ecx, MSR_IA32_MISC_ENABLE\r
+    rdmsr\r
+    or      dx, BIT2                  ; set XD Disable bit if it was set before entering into SMM\r
+    wrmsr\r
+\r
+.7:\r
     rsm\r
 \r
 ASM_PFX(gcSmiHandlerSize): DW $ - _SmiEntryPoint\r
index 4130bf5be5eb0e0d3ad9c3a87831550f3c115c14..cf5ef8217f63c9bc957220510f87306087dd39d9 100644 (file)
@@ -1,6 +1,6 @@
 #------------------------------------------------------------------------------\r
 #\r
-# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 # This program and the accompanying materials\r
 # are licensed and made available under the terms and conditions of the BSD License\r
 # which accompanies this distribution.  The full text of the license may be found at\r
@@ -24,6 +24,7 @@ ASM_GLOBAL  ASM_PFX(PageFaultStubFunction)
 ASM_GLOBAL  ASM_PFX(gSmiMtrrs)\r
 ASM_GLOBAL  ASM_PFX(gcSmiIdtr)\r
 ASM_GLOBAL  ASM_PFX(gcSmiGdtr)\r
+ASM_GLOBAL  ASM_PFX(gTaskGateDescriptor)\r
 ASM_GLOBAL  ASM_PFX(gcPsd)\r
 ASM_GLOBAL  ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))\r
 \r
@@ -236,207 +237,10 @@ ASM_PFX(gcPsd):
 ASM_PFX(gcSmiGdtr):  .word      GDT_SIZE - 1\r
                      .long      NullSeg\r
 \r
-ASM_PFX(gcSmiIdtr):  .word      IDT_SIZE - 1\r
-                     .long      _SmiIDT\r
-\r
-_SmiIDT:\r
-# The following segment repeats 32 times:\r
-# No. 1\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 2\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 3\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 4\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 5\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 6\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 7\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 8\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 9\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 10\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 11\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 12\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 13\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 14\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 15\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 16\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 17\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 18\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 19\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 20\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 21\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 22\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 23\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 24\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 25\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 26\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 27\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 28\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 29\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 30\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 31\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-# No. 32\r
-    .word 0                             # Offset 0:15\r
-    .word      CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-\r
-.equ  IDT_SIZE, . - _SmiIDT\r
-\r
-TaskGateDescriptor:\r
+ASM_PFX(gcSmiIdtr):  .word      0\r
+                     .long      0\r
+\r
+ASM_PFX(gTaskGateDescriptor):\r
     .word      0                        # Reserved\r
     .word      EXCEPTION_TSS_SEL        # TSS Segment selector\r
     .byte      0                        # Reserved\r
@@ -891,21 +695,3 @@ ASM_PFX(PageFaultStubFunction):
 #\r
     clts\r
     iret\r
-\r
-ASM_GLOBAL ASM_PFX(InitializeIDTSmmStackGuard)\r
-ASM_PFX(InitializeIDTSmmStackGuard):\r
-    pushl   %ebx\r
-#\r
-# If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT\r
-# is a Task Gate Descriptor so that when a Page Fault Exception occurs,\r
-# the processors can use a known good stack in case stack ran out.\r
-#\r
-    leal    _SmiIDT + 14 * 8, %ebx\r
-    leal    TaskGateDescriptor, %edx\r
-    movl    (%edx), %eax\r
-    movl    %eax, (%ebx)\r
-    movl    4(%edx), %eax\r
-    movl    %eax, 4(%ebx)\r
-\r
-    popl    %ebx\r
-    ret\r
index b4eb492da0c04e6a015d07cda33b222d9bf92515..7b162f868b943d783620d554a0d2c4c03cdf227a 100644 (file)
@@ -1,5 +1,5 @@
 ;------------------------------------------------------------------------------ ;\r
-; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 ; This program and the accompanying materials\r
 ; are licensed and made available under the terms and conditions of the BSD License\r
 ; which accompanies this distribution.  The full text of the license may be found at\r
@@ -26,6 +26,7 @@ EXTERNDEF   PageFaultStubFunction:PROC
 EXTERNDEF   gSmiMtrrs:QWORD\r
 EXTERNDEF   gcSmiIdtr:FWORD\r
 EXTERNDEF   gcSmiGdtr:FWORD\r
+EXTERNDEF   gTaskGateDescriptor:QWORD\r
 EXTERNDEF   gcPsd:BYTE\r
 EXTERNDEF   FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE\r
 \r
@@ -252,20 +253,10 @@ gcSmiGdtr   LABEL   FWORD
     DD      offset NullSeg\r
 \r
 gcSmiIdtr   LABEL   FWORD\r
-    DW      IDT_SIZE - 1\r
-    DD      offset _SmiIDT\r
-\r
-_SmiIDT     LABEL   QWORD\r
-REPEAT      32\r
-    DW      0                           ; Offset 0:15\r
-    DW      CODE_SEL                    ; Segment selector\r
-    DB      0                           ; Unused\r
-    DB      8eh                         ; Interrupt Gate, Present\r
-    DW      0                           ; Offset 16:31\r
-            ENDM\r
-IDT_SIZE = $ - offset _SmiIDT\r
-\r
-TaskGateDescriptor LABEL DWORD\r
+    DW      0\r
+    DD      0\r
+\r
+gTaskGateDescriptor LABEL QWORD\r
     DW      0                           ; Reserved\r
     DW      EXCEPTION_TSS_SEL           ; TSS Segment selector\r
     DB      0                           ; Reserved\r
@@ -720,19 +711,4 @@ PageFaultStubFunction   PROC
     iretd\r
 PageFaultStubFunction   ENDP\r
 \r
-InitializeIDTSmmStackGuard   PROC    USES    ebx\r
-;\r
-; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT\r
-; is a Task Gate Descriptor so that when a Page Fault Exception occurs,\r
-; the processors can use a known good stack in case stack is ran out.\r
-;\r
-    lea     ebx, _SmiIDT + 14 * 8\r
-    lea     edx, TaskGateDescriptor\r
-    mov     eax, [edx]\r
-    mov     [ebx], eax\r
-    mov     eax, [edx + 4]\r
-    mov     [ebx + 4], eax\r
-    ret\r
-InitializeIDTSmmStackGuard   ENDP\r
-\r
     END\r
index 6a328289a8af5e60ee7df5d13b61a40be86176de..4d58999e90a64f74376e067431d33c3e9897a779 100644 (file)
@@ -1,5 +1,5 @@
 ;------------------------------------------------------------------------------ ;\r
-; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 ; This program and the accompanying materials\r
 ; are licensed and made available under the terms and conditions of the BSD License\r
 ; which accompanies this distribution.  The full text of the license may be found at\r
@@ -24,6 +24,7 @@ extern  ASM_PFX(SmiPFHandler)
 \r
 global  ASM_PFX(gcSmiIdtr)\r
 global  ASM_PFX(gcSmiGdtr)\r
+global  ASM_PFX(gTaskGateDescriptor)\r
 global  ASM_PFX(gcPsd)\r
 \r
     SECTION .data\r
@@ -250,21 +251,10 @@ ASM_PFX(gcSmiGdtr):
     DD      NullSeg\r
 \r
 ASM_PFX(gcSmiIdtr):\r
-    DW      IDT_SIZE - 1\r
-    DD      _SmiIDT\r
+    DW      0\r
+    DD      0\r
 \r
-_SmiIDT:\r
-%rep 32\r
-    DW      0                           ; Offset 0:15\r
-    DW      CODE_SEL                    ; Segment selector\r
-    DB      0                           ; Unused\r
-    DB      0x8e                         ; Interrupt Gate, Present\r
-    DW      0                           ; Offset 16:31\r
-%endrep\r
-\r
-IDT_SIZE equ $ - _SmiIDT\r
-\r
-TaskGateDescriptor:\r
+ASM_PFX(gTaskGateDescriptor):\r
     DW      0                           ; Reserved\r
     DW      EXCEPTION_TSS_SEL           ; TSS Segment selector\r
     DB      0                           ; Reserved\r
@@ -717,19 +707,3 @@ ASM_PFX(PageFaultStubFunction):
     clts\r
     iretd\r
 \r
-global ASM_PFX(InitializeIDTSmmStackGuard)\r
-ASM_PFX(InitializeIDTSmmStackGuard):\r
-    push    ebx\r
-;\r
-; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT\r
-; is a Task Gate Descriptor so that when a Page Fault Exception occurrs,\r
-; the processors can use a known good stack in case stack is ran out.\r
-;\r
-    lea     ebx, [_SmiIDT + 14 * 8]\r
-    lea     edx, [TaskGateDescriptor]\r
-    mov     eax, [edx]\r
-    mov     [ebx], eax\r
-    mov     eax, [edx + 4]\r
-    mov     [ebx + 4], eax\r
-    pop     ebx\r
-    ret\r
index 9760373b4740f055f0170cfe5e1fd3f3144c941f..428169831328b1508096fdd8d019451dbc788317 100644 (file)
@@ -14,6 +14,33 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "PiSmmCpuDxeSmm.h"\r
 \r
+extern UINT64 gTaskGateDescriptor;\r
+\r
+EFI_PHYSICAL_ADDRESS                mGdtBuffer;\r
+UINTN                               mGdtBufferSize;\r
+\r
+/**\r
+  Initialize IDT for SMM Stack Guard.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+InitializeIDTSmmStackGuard (\r
+  VOID\r
+  )\r
+{\r
+  IA32_IDT_GATE_DESCRIPTOR  *IdtGate;\r
+\r
+  //\r
+  // If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT\r
+  // is a Task Gate Descriptor so that when a Page Fault Exception occurs,\r
+  // the processors can use a known good stack in case stack is ran out.\r
+  //\r
+  IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;\r
+  IdtGate += EXCEPT_IA32_PAGE_FAULT;\r
+  IdtGate->Uint64 = gTaskGateDescriptor;\r
+}\r
+\r
 /**\r
   Initialize Gdt for all processors.\r
   \r
@@ -49,8 +76,10 @@ InitGdt (
     gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));\r
 \r
     GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned\r
-    GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));\r
+    mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
+    GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));\r
     ASSERT (GdtTssTables != NULL);\r
+    mGdtBuffer = (UINTN)GdtTssTables;\r
     GdtTableStepSize = GdtTssTableSize;\r
 \r
     for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {\r
@@ -82,8 +111,10 @@ InitGdt (
     // Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory.\r
     //\r
     GdtTssTableSize = gcSmiGdtr.Limit + 1;\r
-    GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));\r
+    mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
+    GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));\r
     ASSERT (GdtTssTables != NULL);\r
+    mGdtBuffer = (UINTN)GdtTssTables;\r
     GdtTableStepSize = GdtTssTableSize;\r
 \r
     for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {\r
index 767cb6908b391472fd7e839a70ca52dda78201c6..724cd92c9c942291e05e5bf1d2f04a1fbe4ddc0b 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 IA-32 processor specific functions to enable SMM profile.\r
 \r
-Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -24,7 +24,7 @@ InitSmmS3Cr3 (
   VOID\r
   )\r
 {\r
-  mSmmS3ResumeState->SmmS3Cr3 = Gen4GPageTable (0, TRUE);\r
+  mSmmS3ResumeState->SmmS3Cr3 = Gen4GPageTable (TRUE);\r
 \r
   return ;\r
 }\r
index 12466ef5de1f633b20c24bcec75e1ffff0c1e586..9b8db90ff6edb465787c972b250a0133aafc6dfe 100644 (file)
@@ -734,14 +734,12 @@ APHandler (
 /**\r
   Create 4G PageTable in SMRAM.\r
 \r
-  @param          ExtraPages       Additional page numbers besides for 4G memory\r
-  @param          Is32BitPageTable Whether the page table is 32-bit PAE\r
+  @param[in]      Is32BitPageTable Whether the page table is 32-bit PAE\r
   @return         PageTable Address\r
 \r
 **/\r
 UINT32\r
 Gen4GPageTable (\r
-  IN      UINTN                     ExtraPages,\r
   IN      BOOLEAN                   Is32BitPageTable\r
   )\r
 {\r
@@ -775,10 +773,10 @@ Gen4GPageTable (
   //\r
   // Allocate the page table\r
   //\r
-  PageTable = AllocatePageTableMemory (ExtraPages + 5 + PagesNeeded);\r
+  PageTable = AllocatePageTableMemory (5 + PagesNeeded);\r
   ASSERT (PageTable != NULL);\r
 \r
-  PageTable = (VOID *)((UINTN)PageTable + EFI_PAGES_TO_SIZE (ExtraPages));\r
+  PageTable = (VOID *)((UINTN)PageTable);\r
   Pte = (UINT64*)PageTable;\r
 \r
   //\r
@@ -903,13 +901,13 @@ SetCacheability (
   PageTable[PTIndex] |= (UINT64)Cacheability;\r
 }\r
 \r
-\r
 /**\r
   Schedule a procedure to run on the specified CPU.\r
 \r
-  @param  Procedure                The address of the procedure to run\r
-  @param  CpuIndex                 Target CPU Index\r
-  @param  ProcArguments            The parameter to pass to the procedure\r
+  @param[in]       Procedure                The address of the procedure to run\r
+  @param[in]       CpuIndex                 Target CPU Index\r
+  @param[in, OUT]  ProcArguments            The parameter to pass to the procedure\r
+  @param[in]       BlockingMode             Startup AP in blocking mode or not\r
 \r
   @retval EFI_INVALID_PARAMETER    CpuNumber not valid\r
   @retval EFI_INVALID_PARAMETER    CpuNumber specifying BSP\r
@@ -919,32 +917,104 @@ SetCacheability (
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
-SmmStartupThisAp (\r
+InternalSmmStartupThisAp (\r
   IN      EFI_AP_PROCEDURE          Procedure,\r
   IN      UINTN                     CpuIndex,\r
-  IN OUT  VOID                      *ProcArguments OPTIONAL\r
+  IN OUT  VOID                      *ProcArguments OPTIONAL,\r
+  IN      BOOLEAN                   BlockingMode\r
   )\r
 {\r
-  if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus ||\r
-      CpuIndex == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu ||\r
-      !(*(mSmmMpSyncData->CpuData[CpuIndex].Present)) ||\r
-      gSmmCpuPrivate->Operation[CpuIndex] == SmmCpuRemove ||\r
-      !AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) {\r
+  if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) {\r
+    DEBUG((DEBUG_ERROR, "CpuIndex(%d) >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus(%d)\n", CpuIndex, gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (CpuIndex == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {\r
+    DEBUG((DEBUG_ERROR, "CpuIndex(%d) == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu\n", CpuIndex));\r
     return EFI_INVALID_PARAMETER;\r
   }\r
+  if (!(*(mSmmMpSyncData->CpuData[CpuIndex].Present))) {\r
+    if (mSmmMpSyncData->EffectiveSyncMode == SmmCpuSyncModeTradition) {\r
+      DEBUG((DEBUG_ERROR, "!mSmmMpSyncData->CpuData[%d].Present\n", CpuIndex));\r
+    }\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (gSmmCpuPrivate->Operation[CpuIndex] == SmmCpuRemove) {\r
+    if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {\r
+      DEBUG((DEBUG_ERROR, "gSmmCpuPrivate->Operation[%d] == SmmCpuRemove\n", CpuIndex));\r
+    }\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BlockingMode) {\r
+    AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
+  } else {\r
+    if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) {\r
+      DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
 \r
   mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;\r
   mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;\r
   ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
 \r
-  if (FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)) {\r
+  if (BlockingMode) {\r
     AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
     ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
   }\r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Schedule a procedure to run on the specified CPU in blocking mode.\r
+\r
+  @param[in]       Procedure                The address of the procedure to run\r
+  @param[in]       CpuIndex                 Target CPU Index\r
+  @param[in, out]  ProcArguments            The parameter to pass to the procedure\r
+\r
+  @retval EFI_INVALID_PARAMETER    CpuNumber not valid\r
+  @retval EFI_INVALID_PARAMETER    CpuNumber specifying BSP\r
+  @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber did not enter SMM\r
+  @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber is busy\r
+  @retval EFI_SUCCESS              The procedure has been successfully scheduled\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBlockingStartupThisAp (\r
+  IN      EFI_AP_PROCEDURE          Procedure,\r
+  IN      UINTN                     CpuIndex,\r
+  IN OUT  VOID                      *ProcArguments OPTIONAL\r
+  )\r
+{\r
+  return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, TRUE);\r
+}\r
+\r
+/**\r
+  Schedule a procedure to run on the specified CPU.\r
+\r
+  @param  Procedure                The address of the procedure to run\r
+  @param  CpuIndex                 Target CPU Index\r
+  @param  ProcArguments            The parameter to pass to the procedure\r
+\r
+  @retval EFI_INVALID_PARAMETER    CpuNumber not valid\r
+  @retval EFI_INVALID_PARAMETER    CpuNumber specifying BSP\r
+  @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber did not enter SMM\r
+  @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber is busy\r
+  @retval EFI_SUCCESS              The procedure has been successfully scheduled\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmStartupThisAp (\r
+  IN      EFI_AP_PROCEDURE          Procedure,\r
+  IN      UINTN                     CpuIndex,\r
+  IN OUT  VOID                      *ProcArguments OPTIONAL\r
+  )\r
+{\r
+  return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, FeaturePcdGet (PcdCpuSmmBlockStartupThisAp));\r
+}\r
+\r
 /**\r
   This function sets DR6 & DR7 according to SMM save state, before running SMM C code.\r
   They are useful when you want to enable hardware breakpoints in SMM without entry SMM mode.\r
@@ -964,6 +1034,7 @@ CpuSmmDebugEntry (
   SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
   \r
   if (FeaturePcdGet (PcdCpuSmmDebug)) {\r
+    ASSERT(CpuIndex < mMaxNumberOfCpus);\r
     CpuSaveState = (SMRAM_SAVE_STATE_MAP *)gSmmCpuPrivate->CpuSaveState[CpuIndex];\r
     if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
       AsmWriteDr6 (CpuSaveState->x86._DR6);\r
@@ -993,6 +1064,7 @@ CpuSmmDebugExit (
   SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
 \r
   if (FeaturePcdGet (PcdCpuSmmDebug)) {\r
+    ASSERT(CpuIndex < mMaxNumberOfCpus);\r
     CpuSaveState = (SMRAM_SAVE_STATE_MAP *)gSmmCpuPrivate->CpuSaveState[CpuIndex];\r
     if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
       CpuSaveState->x86._DR7 = (UINT32)AsmReadDr7 ();\r
@@ -1022,8 +1094,8 @@ SmiRendezvous (
   BOOLEAN                        BspInProgress;\r
   UINTN                          Index;\r
   UINTN                          Cr2;\r
-  BOOLEAN                        XdDisableFlag;\r
-  MSR_IA32_MISC_ENABLE_REGISTER  MiscEnableMsr;\r
+\r
+  ASSERT(CpuIndex < mMaxNumberOfCpus);\r
 \r
   //\r
   // Save Cr2 because Page Fault exception in SMM may override its value\r
@@ -1082,20 +1154,6 @@ SmiRendezvous (
       InitializeSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
     }\r
 \r
-    //\r
-    // Try to enable XD\r
-    //\r
-    XdDisableFlag = FALSE;\r
-    if (mXdSupported) {\r
-      MiscEnableMsr.Uint64 = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);\r
-      if (MiscEnableMsr.Bits.XD == 1) {\r
-        XdDisableFlag = TRUE;\r
-        MiscEnableMsr.Bits.XD = 0;\r
-        AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, MiscEnableMsr.Uint64);\r
-      }\r
-      ActivateXd ();\r
-    }\r
-\r
     if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
       ActivateSmmProfile (CpuIndex);\r
     }\r
@@ -1176,15 +1234,6 @@ SmiRendezvous (
     //\r
     while (*mSmmMpSyncData->AllCpusInSync) {\r
       CpuPause ();\r
-     }\r
-\r
-    //\r
-    // Restore XD\r
-    //\r
-    if (XdDisableFlag) {\r
-      MiscEnableMsr.Uint64 = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);\r
-      MiscEnableMsr.Bits.XD = 1;\r
-      AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, MiscEnableMsr.Uint64);\r
     }\r
   }\r
 \r
index 5f13446015cc0482b1477836fbf5e73d64a37655..4baba1e9f8dc1bbd1a8925be4e6683338d1ffc8c 100644 (file)
@@ -113,6 +113,19 @@ InitializeSmmIdt (
   EFI_STATUS               Status;\r
   BOOLEAN                  InterruptState;\r
   IA32_DESCRIPTOR          DxeIdtr;\r
+\r
+  //\r
+  // There are 32 (not 255) entries in it since only processor\r
+  // generated exceptions will be handled.\r
+  //\r
+  gcSmiIdtr.Limit = (sizeof(IA32_IDT_GATE_DESCRIPTOR) * 32) - 1;\r
+  //\r
+  // Allocate page aligned IDT, because it might be set as read only.\r
+  //\r
+  gcSmiIdtr.Base = (UINTN)AllocateCodePages (EFI_SIZE_TO_PAGES(gcSmiIdtr.Limit + 1));\r
+  ASSERT (gcSmiIdtr.Base != 0);\r
+  ZeroMem ((VOID *)gcSmiIdtr.Base, gcSmiIdtr.Limit + 1);\r
+\r
   //\r
   // Disable Interrupt and save DXE IDT table\r
   //\r
@@ -731,9 +744,9 @@ PiCpuSmmEntry (
   //\r
   BufferPages = EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1));\r
   if ((FamilyId == 4) || (FamilyId == 5)) {\r
-    Buffer = AllocateAlignedPages (BufferPages, SIZE_32KB);\r
+    Buffer = AllocateAlignedCodePages (BufferPages, SIZE_32KB);\r
   } else {\r
-    Buffer = AllocateAlignedPages (BufferPages, SIZE_4KB);\r
+    Buffer = AllocateAlignedCodePages (BufferPages, SIZE_4KB);\r
   }\r
   ASSERT (Buffer != NULL);\r
   DEBUG ((EFI_D_INFO, "SMRAM SaveState Buffer (0x%08x, 0x%08x)\n", Buffer, EFI_PAGES_TO_SIZE(BufferPages)));\r
@@ -842,6 +855,8 @@ PiCpuSmmEntry (
   //\r
   SmmCpuFeaturesSmmRelocationComplete ();\r
 \r
+  DEBUG ((DEBUG_INFO, "mXdSupported - 0x%x\n", mXdSupported));\r
+\r
   //\r
   // SMM Time initialization\r
   //\r
@@ -1137,6 +1152,17 @@ ConfigSmmCodeAccessCheck (
   }\r
 }\r
 \r
+/**\r
+  Set code region to be read only and data region to be execute disable.\r
+**/\r
+VOID\r
+SetRegionAttributes (\r
+  VOID\r
+  )\r
+{\r
+  SetMemMapAttributes ();\r
+}\r
+\r
 /**\r
   This API provides a way to allocate memory for page table.\r
 \r
@@ -1166,6 +1192,109 @@ AllocatePageTableMemory (
   return AllocatePages (Pages);\r
 }\r
 \r
+/**\r
+  Allocate pages for code.\r
+\r
+  @param[in]  Pages Number of pages to be allocated.\r
+\r
+  @return Allocated memory.\r
+**/\r
+VOID *\r
+AllocateCodePages (\r
+  IN UINTN           Pages\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Memory;\r
+\r
+  if (Pages == 0) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, Pages, &Memory);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+  return (VOID *) (UINTN) Memory;\r
+}\r
+\r
+/**\r
+  Allocate aligned pages for code.\r
+\r
+  @param[in]  Pages                 Number of pages to be allocated.\r
+  @param[in]  Alignment             The requested alignment of the allocation.\r
+                                    Must be a power of two.\r
+                                    If Alignment is zero, then byte alignment is used.\r
+\r
+  @return Allocated memory.\r
+**/\r
+VOID *\r
+AllocateAlignedCodePages (\r
+  IN UINTN            Pages,\r
+  IN UINTN            Alignment\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Memory;\r
+  UINTN                 AlignedMemory;\r
+  UINTN                 AlignmentMask;\r
+  UINTN                 UnalignedPages;\r
+  UINTN                 RealPages;\r
+\r
+  //\r
+  // Alignment must be a power of two or zero.\r
+  //\r
+  ASSERT ((Alignment & (Alignment - 1)) == 0);\r
+\r
+  if (Pages == 0) {\r
+    return NULL;\r
+  }\r
+  if (Alignment > EFI_PAGE_SIZE) {\r
+    //\r
+    // Calculate the total number of pages since alignment is larger than page size.\r
+    //\r
+    AlignmentMask  = Alignment - 1;\r
+    RealPages      = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
+    //\r
+    // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
+    //\r
+    ASSERT (RealPages > Pages);\r
+\r
+    Status         = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, RealPages, &Memory);\r
+    if (EFI_ERROR (Status)) {\r
+      return NULL;\r
+    }\r
+    AlignedMemory  = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
+    UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);\r
+    if (UnalignedPages > 0) {\r
+      //\r
+      // Free first unaligned page(s).\r
+      //\r
+      Status = gSmst->SmmFreePages (Memory, UnalignedPages);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+    Memory         = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));\r
+    UnalignedPages = RealPages - Pages - UnalignedPages;\r
+    if (UnalignedPages > 0) {\r
+      //\r
+      // Free last unaligned page(s).\r
+      //\r
+      Status = gSmst->SmmFreePages (Memory, UnalignedPages);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+  } else {\r
+    //\r
+    // Do not over-allocate pages in this case.\r
+    //\r
+    Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, Pages, &Memory);\r
+    if (EFI_ERROR (Status)) {\r
+      return NULL;\r
+    }\r
+    AlignedMemory  = (UINTN) Memory;\r
+  }\r
+  return (VOID *) AlignedMemory;\r
+}\r
+\r
 /**\r
   Perform the remaining tasks.\r
 \r
@@ -1186,6 +1315,17 @@ PerformRemainingTasks (
     // Create a mix of 2MB and 4KB page table. Update some memory ranges absent and execute-disable.\r
     //\r
     InitPaging ();\r
+\r
+    //\r
+    // Mark critical region to be read-only in page table\r
+    //\r
+    SetRegionAttributes ();\r
+\r
+    //\r
+    // Set page table itself to be read-only\r
+    //\r
+    SetPageTableAttributes ();\r
+\r
     //\r
     // Configure SMM Code Access Check feature if available.\r
     //\r
index 88d9c85db6b775f24d0a7b2ff0afeefd4c8b18cf..907526e40680d4965be712bd54e1ef50761e519e 100644 (file)
@@ -25,6 +25,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Protocol/SmmCpuService.h>\r
 \r
 #include <Guid/AcpiS3Context.h>\r
+#include <Guid/PiSmmMemoryAttributesTable.h>\r
 \r
 #include <Library/BaseLib.h>\r
 #include <Library/IoLib.h>\r
@@ -83,13 +84,38 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define IA32_PG_PMNT                BIT62\r
 #define IA32_PG_NX                  BIT63\r
 \r
-#define PAGE_ATTRIBUTE_BITS         (IA32_PG_RW | IA32_PG_P)\r
+#define PAGE_ATTRIBUTE_BITS         (IA32_PG_D | IA32_PG_A | IA32_PG_U | IA32_PG_RW | IA32_PG_P)\r
 //\r
 // Bits 1, 2, 5, 6 are reserved in the IA32 PAE PDPTE\r
 // X64 PAE PDPTE does not have such restriction\r
 //\r
 #define IA32_PAE_PDPTE_ATTRIBUTE_BITS    (IA32_PG_P)\r
 \r
+#define PAGE_PROGATE_BITS           (IA32_PG_NX | PAGE_ATTRIBUTE_BITS)\r
+\r
+#define PAGING_4K_MASK  0xFFF\r
+#define PAGING_2M_MASK  0x1FFFFF\r
+#define PAGING_1G_MASK  0x3FFFFFFF\r
+\r
+#define PAGING_PAE_INDEX_MASK  0x1FF\r
+\r
+#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull\r
+#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull\r
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull\r
+\r
+typedef enum {\r
+  PageNone,\r
+  Page4K,\r
+  Page2M,\r
+  Page1G,\r
+} PAGE_ATTRIBUTE;\r
+\r
+typedef struct {\r
+  PAGE_ATTRIBUTE   Attribute;\r
+  UINT64           Length;\r
+  UINT64           AddressMask;\r
+} PAGE_ATTRIBUTE_TABLE;\r
+\r
 //\r
 // Size of Task-State Segment defined in IA32 Manual\r
 //\r
@@ -98,6 +124,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define TSS_IA32_CR3_OFFSET   28\r
 #define TSS_IA32_ESP_OFFSET   56\r
 \r
+#define CR0_WP                BIT16\r
+\r
 //\r
 // Code select value\r
 //\r
@@ -395,6 +423,8 @@ typedef struct {
 } SMM_CPU_SEMAPHORES;\r
 \r
 extern IA32_DESCRIPTOR                     gcSmiGdtr;\r
+extern EFI_PHYSICAL_ADDRESS                mGdtBuffer;\r
+extern UINTN                               mGdtBufferSize;\r
 extern IA32_DESCRIPTOR                     gcSmiIdtr;\r
 extern VOID                                *gcSmiIdtrPtr;\r
 extern CONST PROCESSOR_SMM_DESCRIPTOR      gcPsd;\r
@@ -414,14 +444,12 @@ extern SPIN_LOCK                           *mMemoryMappedLock;
 /**\r
   Create 4G PageTable in SMRAM.\r
 \r
-  @param          ExtraPages       Additional page numbers besides for 4G memory\r
-  @param          Is32BitPageTable Whether the page table is 32-bit PAE\r
+  @param[in]      Is32BitPageTable Whether the page table is 32-bit PAE\r
   @return         PageTable Address\r
 \r
 **/\r
 UINT32\r
 Gen4GPageTable (\r
-  IN      UINTN                     ExtraPages,\r
   IN      BOOLEAN                   Is32BitPageTable\r
   );\r
 \r
@@ -482,7 +510,7 @@ InitializeIDTSmmStackGuard (
 \r
 /**\r
   Initialize Gdt for all processors.\r
-  \r
+\r
   @param[in]   Cr3          CR3 value.\r
   @param[out]  GdtStepSize  The step size for GDT table.\r
 \r
@@ -760,6 +788,96 @@ DumpModuleInfoByIp (
   IN  UINTN              CallerIpAddress\r
   );\r
 \r
+/**\r
+  This function sets memory attribute according to MemoryAttributesTable.\r
+**/\r
+VOID\r
+SetMemMapAttributes (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  This function sets memory attribute for page table.\r
+**/\r
+VOID\r
+SetPageTableAttributes (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Return page table base.\r
+\r
+  @return page table base.\r
+**/\r
+UINTN\r
+GetPageTableBase (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  This function sets the attributes for the memory region specified by BaseAddress and\r
+  Length from their current attributes to the attributes specified by Attributes.\r
+\r
+  @param[in]   BaseAddress      The physical address that is the start address of a memory region.\r
+  @param[in]   Length           The size in bytes of the memory region.\r
+  @param[in]   Attributes       The bit mask of attributes to set for the memory region.\r
+  @param[out]  IsSplitted       TRUE means page table splitted. FALSE means page table not splitted.\r
+\r
+  @retval EFI_SUCCESS           The attributes were set for the memory region.\r
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by\r
+                                BaseAddress and Length cannot be modified.\r
+  @retval EFI_INVALID_PARAMETER Length is zero.\r
+                                Attributes specified an illegal combination of attributes that\r
+                                cannot be set together.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of\r
+                                the memory resource range.\r
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory\r
+                                resource range specified by BaseAddress and Length.\r
+                                The bit mask of attributes is not support for the memory resource\r
+                                range specified by BaseAddress and Length.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmSetMemoryAttributesEx (\r
+  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,\r
+  IN  UINT64                                     Length,\r
+  IN  UINT64                                     Attributes,\r
+  OUT BOOLEAN                                    *IsSplitted  OPTIONAL\r
+  );\r
+\r
+/**\r
+  This function clears the attributes for the memory region specified by BaseAddress and\r
+  Length from their current attributes to the attributes specified by Attributes.\r
+\r
+  @param[in]   BaseAddress      The physical address that is the start address of a memory region.\r
+  @param[in]   Length           The size in bytes of the memory region.\r
+  @param[in]   Attributes       The bit mask of attributes to clear for the memory region.\r
+  @param[out]  IsSplitted       TRUE means page table splitted. FALSE means page table not splitted.\r
+\r
+  @retval EFI_SUCCESS           The attributes were cleared for the memory region.\r
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by\r
+                                BaseAddress and Length cannot be modified.\r
+  @retval EFI_INVALID_PARAMETER Length is zero.\r
+                                Attributes specified an illegal combination of attributes that\r
+                                cannot be set together.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of\r
+                                the memory resource range.\r
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory\r
+                                resource range specified by BaseAddress and Length.\r
+                                The bit mask of attributes is not support for the memory resource\r
+                                range specified by BaseAddress and Length.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmClearMemoryAttributesEx (\r
+  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,\r
+  IN  UINT64                                     Length,\r
+  IN  UINT64                                     Attributes,\r
+  OUT BOOLEAN                                    *IsSplitted  OPTIONAL\r
+  );\r
+\r
 /**\r
   This API provides a way to allocate memory for page table.\r
 \r
@@ -780,6 +898,34 @@ AllocatePageTableMemory (
   IN UINTN           Pages\r
   );\r
 \r
+/**\r
+  Allocate pages for code.\r
+\r
+  @param[in]  Pages Number of pages to be allocated.\r
+\r
+  @return Allocated memory.\r
+**/\r
+VOID *\r
+AllocateCodePages (\r
+  IN UINTN           Pages\r
+  );\r
+\r
+/**\r
+  Allocate aligned pages for code.\r
+\r
+  @param[in]  Pages                 Number of pages to be allocated.\r
+  @param[in]  Alignment             The requested alignment of the allocation.\r
+                                    Must be a power of two.\r
+                                    If Alignment is zero, then byte alignment is used.\r
+\r
+  @return Allocated memory.\r
+**/\r
+VOID *\r
+AllocateAlignedCodePages (\r
+  IN UINTN            Pages,\r
+  IN UINTN            Alignment\r
+  );\r
+\r
 \r
 //\r
 // S3 related global variable and function prototype.\r
index 5d598d609cbef1e524963f43c7807af6c23fc8de..d409edfe971a74bb8fbae5be2f8e0d94dd5c4c13 100644 (file)
@@ -4,7 +4,7 @@
 # This SMM driver performs SMM initialization, deploy SMM Entry Vector,\r
 # provides CPU specific services in SMM.\r
 #\r
-# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 #\r
 # This program and the accompanying materials\r
 # are licensed and made available under the terms and conditions of the BSD License\r
@@ -44,6 +44,7 @@
   SmmProfile.h\r
   SmmProfileInternal.h\r
   SmramSaveState.c\r
+  SmmCpuMemoryManagement.c\r
 \r
 [Sources.Ia32]\r
   Ia32/Semaphore.c\r
   gEfiGlobalVariableGuid                   ## SOMETIMES_PRODUCES ## Variable:L"SmmProfileData"\r
   gEfiAcpi20TableGuid                      ## SOMETIMES_CONSUMES ## SystemTable\r
   gEfiAcpi10TableGuid                      ## SOMETIMES_CONSUMES ## SystemTable\r
+  gEdkiiPiSmmMemoryAttributesTableGuid     ## CONSUMES ## SystemTable\r
 \r
 [FeaturePcd]\r
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmDebug                         ## CONSUMES\r
   gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress               ## SOMETIMES_PRODUCES\r
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmCodeAccessCheckEnable         ## CONSUMES\r
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode                      ## CONSUMES\r
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStaticPageTable               ## CONSUMES\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable                   ## CONSUMES\r
 \r
 [Depex]\r
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
new file mode 100644 (file)
index 0000000..b4f8861
--- /dev/null
@@ -0,0 +1,871 @@
+/** @file\r
+\r
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "PiSmmCpuDxeSmm.h"\r
+\r
+#define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \\r
+  ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))\r
+\r
+PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {\r
+  {Page4K,  SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},\r
+  {Page2M,  SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},\r
+  {Page1G,  SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},\r
+};\r
+\r
+/**\r
+  Return page table base.\r
+\r
+  @return page table base.\r
+**/\r
+UINTN\r
+GetPageTableBase (\r
+  VOID\r
+  )\r
+{\r
+  return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);\r
+}\r
+\r
+/**\r
+  Return length according to page attributes.\r
+\r
+  @param[in]  PageAttributes   The page attribute of the page entry.\r
+\r
+  @return The length of page entry.\r
+**/\r
+UINTN\r
+PageAttributeToLength (\r
+  IN PAGE_ATTRIBUTE  PageAttribute\r
+  )\r
+{\r
+  UINTN  Index;\r
+  for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {\r
+    if (PageAttribute == mPageAttributeTable[Index].Attribute) {\r
+      return (UINTN)mPageAttributeTable[Index].Length;\r
+    }\r
+  }\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Return address mask according to page attributes.\r
+\r
+  @param[in]  PageAttributes   The page attribute of the page entry.\r
+\r
+  @return The address mask of page entry.\r
+**/\r
+UINTN\r
+PageAttributeToMask (\r
+  IN PAGE_ATTRIBUTE  PageAttribute\r
+  )\r
+{\r
+  UINTN  Index;\r
+  for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {\r
+    if (PageAttribute == mPageAttributeTable[Index].Attribute) {\r
+      return (UINTN)mPageAttributeTable[Index].AddressMask;\r
+    }\r
+  }\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Return page table entry to match the address.\r
+\r
+  @param[in]   Address          The address to be checked.\r
+  @param[out]  PageAttributes   The page attribute of the page entry.\r
+\r
+  @return The page entry.\r
+**/\r
+VOID *\r
+GetPageTableEntry (\r
+  IN  PHYSICAL_ADDRESS                  Address,\r
+  OUT PAGE_ATTRIBUTE                    *PageAttribute\r
+  )\r
+{\r
+  UINTN                 Index1;\r
+  UINTN                 Index2;\r
+  UINTN                 Index3;\r
+  UINTN                 Index4;\r
+  UINT64                *L1PageTable;\r
+  UINT64                *L2PageTable;\r
+  UINT64                *L3PageTable;\r
+  UINT64                *L4PageTable;\r
+\r
+  Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK;\r
+  Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;\r
+  Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;\r
+  Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;\r
+\r
+  if (sizeof(UINTN) == sizeof(UINT64)) {\r
+    L4PageTable = (UINT64 *)GetPageTableBase ();\r
+    if (L4PageTable[Index4] == 0) {\r
+      *PageAttribute = PageNone;\r
+      return NULL;\r
+    }\r
+\r
+    L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);\r
+  } else {\r
+    L3PageTable = (UINT64 *)GetPageTableBase ();\r
+  }\r
+  if (L3PageTable[Index3] == 0) {\r
+    *PageAttribute = PageNone;\r
+    return NULL;\r
+  }\r
+  if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {\r
+    // 1G\r
+    *PageAttribute = Page1G;\r
+    return &L3PageTable[Index3];\r
+  }\r
+\r
+  L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);\r
+  if (L2PageTable[Index2] == 0) {\r
+    *PageAttribute = PageNone;\r
+    return NULL;\r
+  }\r
+  if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
+    // 2M\r
+    *PageAttribute = Page2M;\r
+    return &L2PageTable[Index2];\r
+  }\r
+\r
+  // 4k\r
+  L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);\r
+  if ((L1PageTable[Index1] == 0) && (Address != 0)) {\r
+    *PageAttribute = PageNone;\r
+    return NULL;\r
+  }\r
+  *PageAttribute = Page4K;\r
+  return &L1PageTable[Index1];\r
+}\r
+\r
+/**\r
+  Return memory attributes of page entry.\r
+\r
+  @param[in]  PageEntry        The page entry.\r
+\r
+  @return Memory attributes of page entry.\r
+**/\r
+UINT64\r
+GetAttributesFromPageEntry (\r
+  IN  UINT64                            *PageEntry\r
+  )\r
+{\r
+  UINT64  Attributes;\r
+  Attributes = 0;\r
+  if ((*PageEntry & IA32_PG_P) == 0) {\r
+    Attributes |= EFI_MEMORY_RP;\r
+  }\r
+  if ((*PageEntry & IA32_PG_RW) == 0) {\r
+    Attributes |= EFI_MEMORY_RO;\r
+  }\r
+  if ((*PageEntry & IA32_PG_NX) != 0) {\r
+    Attributes |= EFI_MEMORY_XP;\r
+  }\r
+  return Attributes;\r
+}\r
+\r
+/**\r
+  Modify memory attributes of page entry.\r
+\r
+  @param[in]   PageEntry        The page entry.\r
+  @param[in]   Attributes       The bit mask of attributes to modify for the memory region.\r
+  @param[in]   IsSet            TRUE means to set attributes. FALSE means to clear attributes.\r
+  @param[out]  IsModified       TRUE means page table modified. FALSE means page table not modified.\r
+**/\r
+VOID\r
+ConvertPageEntryAttribute (\r
+  IN  UINT64                            *PageEntry,\r
+  IN  UINT64                            Attributes,\r
+  IN  BOOLEAN                           IsSet,\r
+  OUT BOOLEAN                           *IsModified\r
+  )\r
+{\r
+  UINT64  CurrentPageEntry;\r
+  UINT64  NewPageEntry;\r
+\r
+  CurrentPageEntry = *PageEntry;\r
+  NewPageEntry = CurrentPageEntry;\r
+  if ((Attributes & EFI_MEMORY_RP) != 0) {\r
+    if (IsSet) {\r
+      NewPageEntry &= ~(UINT64)IA32_PG_P;\r
+    } else {\r
+      NewPageEntry |= IA32_PG_P;\r
+    }\r
+  }\r
+  if ((Attributes & EFI_MEMORY_RO) != 0) {\r
+    if (IsSet) {\r
+      NewPageEntry &= ~(UINT64)IA32_PG_RW;\r
+    } else {\r
+      NewPageEntry |= IA32_PG_RW;\r
+    }\r
+  }\r
+  if ((Attributes & EFI_MEMORY_XP) != 0) {\r
+    if (IsSet) {\r
+      NewPageEntry |= IA32_PG_NX;\r
+    } else {\r
+      NewPageEntry &= ~IA32_PG_NX;\r
+    }\r
+  }\r
+  *PageEntry = NewPageEntry;\r
+  if (CurrentPageEntry != NewPageEntry) {\r
+    *IsModified = TRUE;\r
+    DEBUG ((DEBUG_VERBOSE, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));\r
+    DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));\r
+  } else {\r
+    *IsModified = FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  This function returns if there is need to split page entry.\r
+\r
+  @param[in]  BaseAddress      The base address to be checked.\r
+  @param[in]  Length           The length to be checked.\r
+  @param[in]  PageEntry        The page entry to be checked.\r
+  @param[in]  PageAttribute    The page attribute of the page entry.\r
+\r
+  @retval SplitAttributes on if there is need to split page entry.\r
+**/\r
+PAGE_ATTRIBUTE\r
+NeedSplitPage (\r
+  IN  PHYSICAL_ADDRESS                  BaseAddress,\r
+  IN  UINT64                            Length,\r
+  IN  UINT64                            *PageEntry,\r
+  IN  PAGE_ATTRIBUTE                    PageAttribute\r
+  )\r
+{\r
+  UINT64                PageEntryLength;\r
+\r
+  PageEntryLength = PageAttributeToLength (PageAttribute);\r
+\r
+  if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {\r
+    return PageNone;\r
+  }\r
+\r
+  if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {\r
+    return Page4K;\r
+  }\r
+\r
+  return Page2M;\r
+}\r
+\r
+/**\r
+  This function splits one page entry to small page entries.\r
+\r
+  @param[in]  PageEntry        The page entry to be splitted.\r
+  @param[in]  PageAttribute    The page attribute of the page entry.\r
+  @param[in]  SplitAttribute   How to split the page entry.\r
+\r
+  @retval RETURN_SUCCESS            The page entry is splitted.\r
+  @retval RETURN_UNSUPPORTED        The page entry does not support to be splitted.\r
+  @retval RETURN_OUT_OF_RESOURCES   No resource to split page entry.\r
+**/\r
+RETURN_STATUS\r
+SplitPage (\r
+  IN  UINT64                            *PageEntry,\r
+  IN  PAGE_ATTRIBUTE                    PageAttribute,\r
+  IN  PAGE_ATTRIBUTE                    SplitAttribute\r
+  )\r
+{\r
+  UINT64   BaseAddress;\r
+  UINT64   *NewPageEntry;\r
+  UINTN    Index;\r
+\r
+  ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);\r
+\r
+  if (PageAttribute == Page2M) {\r
+    //\r
+    // Split 2M to 4K\r
+    //\r
+    ASSERT (SplitAttribute == Page4K);\r
+    if (SplitAttribute == Page4K) {\r
+      NewPageEntry = AllocatePageTableMemory (1);\r
+      DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));\r
+      if (NewPageEntry == NULL) {\r
+        return RETURN_OUT_OF_RESOURCES;\r
+      }\r
+      BaseAddress = *PageEntry & PAGING_2M_ADDRESS_MASK_64;\r
+      for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
+        NewPageEntry[Index] = BaseAddress + SIZE_4KB * Index + ((*PageEntry) & PAGE_PROGATE_BITS);\r
+      }\r
+      (*PageEntry) = (UINT64)(UINTN)NewPageEntry + ((*PageEntry) & PAGE_PROGATE_BITS);\r
+      return RETURN_SUCCESS;\r
+    } else {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+  } else if (PageAttribute == Page1G) {\r
+    //\r
+    // Split 1G to 2M\r
+    // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.\r
+    //\r
+    ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);\r
+    if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {\r
+      NewPageEntry = AllocatePageTableMemory (1);\r
+      DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));\r
+      if (NewPageEntry == NULL) {\r
+        return RETURN_OUT_OF_RESOURCES;\r
+      }\r
+      BaseAddress = *PageEntry & PAGING_1G_ADDRESS_MASK_64;\r
+      for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
+        NewPageEntry[Index] = BaseAddress + SIZE_2MB * Index + IA32_PG_PS + ((*PageEntry) & PAGE_PROGATE_BITS);\r
+      }\r
+      (*PageEntry) = (UINT64)(UINTN)NewPageEntry + ((*PageEntry) & PAGE_PROGATE_BITS);\r
+      return RETURN_SUCCESS;\r
+    } else {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+  } else {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+}\r
+\r
+/**\r
+  This function modifies the page attributes for the memory region specified by BaseAddress and\r
+  Length from their current attributes to the attributes specified by Attributes.\r
+\r
+  Caller should make sure BaseAddress and Length is at page boundary.\r
+\r
+  @param[in]   BaseAddress      The physical address that is the start address of a memory region.\r
+  @param[in]   Length           The size in bytes of the memory region.\r
+  @param[in]   Attributes       The bit mask of attributes to modify for the memory region.\r
+  @param[in]   IsSet            TRUE means to set attributes. FALSE means to clear attributes.\r
+  @param[out]  IsSplitted       TRUE means page table splitted. FALSE means page table not splitted.\r
+  @param[out]  IsModified       TRUE means page table modified. FALSE means page table not modified.\r
+\r
+  @retval RETURN_SUCCESS           The attributes were modified for the memory region.\r
+  @retval RETURN_ACCESS_DENIED     The attributes for the memory resource range specified by\r
+                                   BaseAddress and Length cannot be modified.\r
+  @retval RETURN_INVALID_PARAMETER Length is zero.\r
+                                   Attributes specified an illegal combination of attributes that\r
+                                   cannot be set together.\r
+  @retval RETURN_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of\r
+                                   the memory resource range.\r
+  @retval RETURN_UNSUPPORTED       The processor does not support one or more bytes of the memory\r
+                                   resource range specified by BaseAddress and Length.\r
+                                   The bit mask of attributes is not support for the memory resource\r
+                                   range specified by BaseAddress and Length.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+ConvertMemoryPageAttributes (\r
+  IN  PHYSICAL_ADDRESS                  BaseAddress,\r
+  IN  UINT64                            Length,\r
+  IN  UINT64                            Attributes,\r
+  IN  BOOLEAN                           IsSet,\r
+  OUT BOOLEAN                           *IsSplitted,  OPTIONAL\r
+  OUT BOOLEAN                           *IsModified   OPTIONAL\r
+  )\r
+{\r
+  UINT64                            *PageEntry;\r
+  PAGE_ATTRIBUTE                    PageAttribute;\r
+  UINTN                             PageEntryLength;\r
+  PAGE_ATTRIBUTE                    SplitAttribute;\r
+  RETURN_STATUS                     Status;\r
+  BOOLEAN                           IsEntryModified;\r
+\r
+  ASSERT (Attributes != 0);\r
+  ASSERT ((Attributes & ~(EFI_MEMORY_RP | EFI_MEMORY_RO | EFI_MEMORY_XP)) == 0);\r
+\r
+  ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);\r
+  ASSERT ((Length & (SIZE_4KB - 1)) == 0);\r
+\r
+  if (Length == 0) {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+\r
+//  DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));\r
+\r
+  if (IsSplitted != NULL) {\r
+    *IsSplitted = FALSE;\r
+  }\r
+  if (IsModified != NULL) {\r
+    *IsModified = FALSE;\r
+  }\r
+\r
+  //\r
+  // Below logic is to check 2M/4K page to make sure we donot waist memory.\r
+  //\r
+  while (Length != 0) {\r
+    PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute);\r
+    if (PageEntry == NULL) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+    PageEntryLength = PageAttributeToLength (PageAttribute);\r
+    SplitAttribute = NeedSplitPage (BaseAddress, Length, PageEntry, PageAttribute);\r
+    if (SplitAttribute == PageNone) {\r
+      ConvertPageEntryAttribute (PageEntry, Attributes, IsSet, &IsEntryModified);\r
+      if (IsEntryModified) {\r
+        if (IsModified != NULL) {\r
+          *IsModified = TRUE;\r
+        }\r
+      }\r
+      //\r
+      // Convert success, move to next\r
+      //\r
+      BaseAddress += PageEntryLength;\r
+      Length -= PageEntryLength;\r
+    } else {\r
+      Status = SplitPage (PageEntry, PageAttribute, SplitAttribute);\r
+      if (RETURN_ERROR (Status)) {\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+      if (IsSplitted != NULL) {\r
+        *IsSplitted = TRUE;\r
+      }\r
+      if (IsModified != NULL) {\r
+        *IsModified = TRUE;\r
+      }\r
+      //\r
+      // Just split current page\r
+      // Convert success in next around\r
+      //\r
+    }\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  FlushTlb on current processor.\r
+\r
+  @param[in,out] Buffer  Pointer to private data buffer.\r
+**/\r
+VOID\r
+EFIAPI\r
+FlushTlbOnCurrentProcessor (\r
+  IN OUT VOID  *Buffer\r
+  )\r
+{\r
+  CpuFlushTlb ();\r
+}\r
+\r
+/**\r
+  FlushTlb for all processors.\r
+**/\r
+VOID\r
+FlushTlbForAll (\r
+  VOID\r
+  )\r
+{\r
+  UINTN       Index;\r
+\r
+  FlushTlbOnCurrentProcessor (NULL);\r
+\r
+  for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {\r
+    if (Index != gSmst->CurrentlyExecutingCpu) {\r
+      // Force to start up AP in blocking mode,\r
+      SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor, Index, NULL);\r
+      // Do not check return status, because AP might not be present in some corner cases.\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  This function sets the attributes for the memory region specified by BaseAddress and\r
+  Length from their current attributes to the attributes specified by Attributes.\r
+\r
+  @param[in]   BaseAddress      The physical address that is the start address of a memory region.\r
+  @param[in]   Length           The size in bytes of the memory region.\r
+  @param[in]   Attributes       The bit mask of attributes to set for the memory region.\r
+  @param[out]  IsSplitted       TRUE means page table splitted. FALSE means page table not splitted.\r
+\r
+  @retval EFI_SUCCESS           The attributes were set for the memory region.\r
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by\r
+                                BaseAddress and Length cannot be modified.\r
+  @retval EFI_INVALID_PARAMETER Length is zero.\r
+                                Attributes specified an illegal combination of attributes that\r
+                                cannot be set together.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of\r
+                                the memory resource range.\r
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory\r
+                                resource range specified by BaseAddress and Length.\r
+                                The bit mask of attributes is not support for the memory resource\r
+                                range specified by BaseAddress and Length.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmSetMemoryAttributesEx (\r
+  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,\r
+  IN  UINT64                                     Length,\r
+  IN  UINT64                                     Attributes,\r
+  OUT BOOLEAN                                    *IsSplitted  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  BOOLEAN     IsModified;\r
+\r
+  Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, TRUE, IsSplitted, &IsModified);\r
+  if (!EFI_ERROR(Status)) {\r
+    if (IsModified) {\r
+      //\r
+      // Flush TLB as last step\r
+      //\r
+      FlushTlbForAll();\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function clears the attributes for the memory region specified by BaseAddress and\r
+  Length from their current attributes to the attributes specified by Attributes.\r
+\r
+  @param[in]   BaseAddress      The physical address that is the start address of a memory region.\r
+  @param[in]   Length           The size in bytes of the memory region.\r
+  @param[in]   Attributes       The bit mask of attributes to clear for the memory region.\r
+  @param[out]  IsSplitted       TRUE means page table splitted. FALSE means page table not splitted.\r
+\r
+  @retval EFI_SUCCESS           The attributes were cleared for the memory region.\r
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by\r
+                                BaseAddress and Length cannot be modified.\r
+  @retval EFI_INVALID_PARAMETER Length is zero.\r
+                                Attributes specified an illegal combination of attributes that\r
+                                cannot be set together.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of\r
+                                the memory resource range.\r
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory\r
+                                resource range specified by BaseAddress and Length.\r
+                                The bit mask of attributes is not support for the memory resource\r
+                                range specified by BaseAddress and Length.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmClearMemoryAttributesEx (\r
+  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,\r
+  IN  UINT64                                     Length,\r
+  IN  UINT64                                     Attributes,\r
+  OUT BOOLEAN                                    *IsSplitted  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  BOOLEAN     IsModified;\r
+\r
+  Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, FALSE, IsSplitted, &IsModified);\r
+  if (!EFI_ERROR(Status)) {\r
+    if (IsModified) {\r
+      //\r
+      // Flush TLB as last step\r
+      //\r
+      FlushTlbForAll();\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function sets the attributes for the memory region specified by BaseAddress and\r
+  Length from their current attributes to the attributes specified by Attributes.\r
+\r
+  @param[in]  BaseAddress      The physical address that is the start address of a memory region.\r
+  @param[in]  Length           The size in bytes of the memory region.\r
+  @param[in]  Attributes       The bit mask of attributes to set for the memory region.\r
+\r
+  @retval EFI_SUCCESS           The attributes were set for the memory region.\r
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by\r
+                                BaseAddress and Length cannot be modified.\r
+  @retval EFI_INVALID_PARAMETER Length is zero.\r
+                                Attributes specified an illegal combination of attributes that\r
+                                cannot be set together.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of\r
+                                the memory resource range.\r
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory\r
+                                resource range specified by BaseAddress and Length.\r
+                                The bit mask of attributes is not support for the memory resource\r
+                                range specified by BaseAddress and Length.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmSetMemoryAttributes (\r
+  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,\r
+  IN  UINT64                                     Length,\r
+  IN  UINT64                                     Attributes\r
+  )\r
+{\r
+  return SmmSetMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);\r
+}\r
+\r
+/**\r
+  This function clears the attributes for the memory region specified by BaseAddress and\r
+  Length from their current attributes to the attributes specified by Attributes.\r
+\r
+  @param[in]  BaseAddress      The physical address that is the start address of a memory region.\r
+  @param[in]  Length           The size in bytes of the memory region.\r
+  @param[in]  Attributes       The bit mask of attributes to clear for the memory region.\r
+\r
+  @retval EFI_SUCCESS           The attributes were cleared for the memory region.\r
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by\r
+                                BaseAddress and Length cannot be modified.\r
+  @retval EFI_INVALID_PARAMETER Length is zero.\r
+                                Attributes specified an illegal combination of attributes that\r
+                                cannot be set together.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of\r
+                                the memory resource range.\r
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory\r
+                                resource range specified by BaseAddress and Length.\r
+                                The bit mask of attributes is not support for the memory resource\r
+                                range specified by BaseAddress and Length.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmClearMemoryAttributes (\r
+  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,\r
+  IN  UINT64                                     Length,\r
+  IN  UINT64                                     Attributes\r
+  )\r
+{\r
+  return SmmClearMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);\r
+}\r
+\r
+\r
+\r
+/**\r
+  Retrieves a pointer to the system configuration table from the SMM System Table\r
+  based on a specified GUID.\r
+\r
+  @param[in]   TableGuid       The pointer to table's GUID type.\r
+  @param[out]  Table           The pointer to the table associated with TableGuid in the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS     A configuration table matching TableGuid was found.\r
+  @retval EFI_NOT_FOUND   A configuration table matching TableGuid could not be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmGetSystemConfigurationTable (\r
+  IN  EFI_GUID  *TableGuid,\r
+  OUT VOID      **Table\r
+  )\r
+{\r
+  UINTN             Index;\r
+\r
+  ASSERT (TableGuid != NULL);\r
+  ASSERT (Table != NULL);\r
+\r
+  *Table = NULL;\r
+  for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) {\r
+    if (CompareGuid (TableGuid, &(gSmst->SmmConfigurationTable[Index].VendorGuid))) {\r
+      *Table = gSmst->SmmConfigurationTable[Index].VendorTable;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  This function sets SMM save state buffer to be RW and XP.\r
+**/\r
+VOID\r
+PatchSmmSaveStateMap (\r
+  VOID\r
+  )\r
+{\r
+  UINTN  Index;\r
+  UINTN  TileCodeSize;\r
+  UINTN  TileDataSize;\r
+  UINTN  TileSize;\r
+\r
+  TileCodeSize = GetSmiHandlerSize ();\r
+  TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);\r
+  TileDataSize = sizeof (SMRAM_SAVE_STATE_MAP) + sizeof (PROCESSOR_SMM_DESCRIPTOR);\r
+  TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);\r
+  TileSize = TileDataSize + TileCodeSize - 1;\r
+  TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);\r
+\r
+  DEBUG ((DEBUG_INFO, "PatchSmmSaveStateMap:\n"));\r
+  for (Index = 0; Index < mMaxNumberOfCpus - 1; Index++) {\r
+    //\r
+    // Code\r
+    //\r
+    SmmSetMemoryAttributes (\r
+      mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,\r
+      TileCodeSize,\r
+      EFI_MEMORY_RO\r
+      );\r
+    SmmClearMemoryAttributes (\r
+      mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,\r
+      TileCodeSize,\r
+      EFI_MEMORY_XP\r
+      );\r
+\r
+    //\r
+    // Data\r
+    //\r
+    SmmClearMemoryAttributes (\r
+      mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,\r
+      TileSize - TileCodeSize,\r
+      EFI_MEMORY_RO\r
+      );\r
+    SmmSetMemoryAttributes (\r
+      mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,\r
+      TileSize - TileCodeSize,\r
+      EFI_MEMORY_XP\r
+      );\r
+  }\r
+\r
+  //\r
+  // Code\r
+  //\r
+  SmmSetMemoryAttributes (\r
+    mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,\r
+    TileCodeSize,\r
+    EFI_MEMORY_RO\r
+    );\r
+  SmmClearMemoryAttributes (\r
+    mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,\r
+    TileCodeSize,\r
+    EFI_MEMORY_XP\r
+    );\r
+\r
+  //\r
+  // Data\r
+  //\r
+  SmmClearMemoryAttributes (\r
+    mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,\r
+    SIZE_32KB - TileCodeSize,\r
+    EFI_MEMORY_RO\r
+    );\r
+  SmmSetMemoryAttributes (\r
+    mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,\r
+    SIZE_32KB - TileCodeSize,\r
+    EFI_MEMORY_XP\r
+    );\r
+}\r
+\r
+/**\r
+  This function sets GDT/IDT buffer to be RO and XP.\r
+**/\r
+VOID\r
+PatchGdtIdtMap (\r
+  VOID\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS       BaseAddress;\r
+  UINTN                      Size;\r
+\r
+  //\r
+  // GDT\r
+  //\r
+  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));\r
+\r
+  BaseAddress = mGdtBuffer;\r
+  Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);\r
+  SmmSetMemoryAttributes (\r
+    BaseAddress,\r
+    Size,\r
+    EFI_MEMORY_RO\r
+    );\r
+  SmmSetMemoryAttributes (\r
+    BaseAddress,\r
+    Size,\r
+    EFI_MEMORY_XP\r
+    );\r
+\r
+  //\r
+  // IDT\r
+  //\r
+  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));\r
+\r
+  BaseAddress = gcSmiIdtr.Base;\r
+  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);\r
+  SmmSetMemoryAttributes (\r
+    BaseAddress,\r
+    Size,\r
+    EFI_MEMORY_RO\r
+    );\r
+  SmmSetMemoryAttributes (\r
+    BaseAddress,\r
+    Size,\r
+    EFI_MEMORY_XP\r
+    );\r
+}\r
+\r
+/**\r
+  This function sets memory attribute according to MemoryAttributesTable.\r
+**/\r
+VOID\r
+SetMemMapAttributes (\r
+  VOID\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR                     *MemoryMap;\r
+  EFI_MEMORY_DESCRIPTOR                     *MemoryMapStart;\r
+  UINTN                                     MemoryMapEntryCount;\r
+  UINTN                                     DescriptorSize;\r
+  UINTN                                     Index;\r
+  EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE      *MemoryAttributesTable;\r
+\r
+  SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);\r
+  if (MemoryAttributesTable == NULL) {\r
+    DEBUG ((DEBUG_INFO, "MemoryAttributesTable - NULL\n"));\r
+    return ;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "MemoryAttributesTable:\n"));\r
+  DEBUG ((DEBUG_INFO, "  Version                   - 0x%08x\n", MemoryAttributesTable->Version));\r
+  DEBUG ((DEBUG_INFO, "  NumberOfEntries           - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));\r
+  DEBUG ((DEBUG_INFO, "  DescriptorSize            - 0x%08x\n", MemoryAttributesTable->DescriptorSize));\r
+\r
+  MemoryMapEntryCount = MemoryAttributesTable->NumberOfEntries;\r
+  DescriptorSize = MemoryAttributesTable->DescriptorSize;\r
+  MemoryMapStart = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);\r
+  MemoryMap = MemoryMapStart;\r
+  for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
+    DEBUG ((DEBUG_INFO, "Entry (0x%x)\n", MemoryMap));\r
+    DEBUG ((DEBUG_INFO, "  Type              - 0x%x\n", MemoryMap->Type));\r
+    DEBUG ((DEBUG_INFO, "  PhysicalStart     - 0x%016lx\n", MemoryMap->PhysicalStart));\r
+    DEBUG ((DEBUG_INFO, "  VirtualStart      - 0x%016lx\n", MemoryMap->VirtualStart));\r
+    DEBUG ((DEBUG_INFO, "  NumberOfPages     - 0x%016lx\n", MemoryMap->NumberOfPages));\r
+    DEBUG ((DEBUG_INFO, "  Attribute         - 0x%016lx\n", MemoryMap->Attribute));\r
+    MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);\r
+  }\r
+\r
+  MemoryMap = MemoryMapStart;\r
+  for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
+    DEBUG ((DEBUG_VERBOSE, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap->PhysicalStart, MemoryMap->NumberOfPages));\r
+    switch (MemoryMap->Type) {\r
+    case EfiRuntimeServicesCode:\r
+      SmmSetMemoryAttributes (\r
+        MemoryMap->PhysicalStart,\r
+        EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),\r
+        EFI_MEMORY_RO\r
+        );\r
+      break;\r
+    case EfiRuntimeServicesData:\r
+      SmmSetMemoryAttributes (\r
+        MemoryMap->PhysicalStart,\r
+        EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),\r
+        EFI_MEMORY_XP\r
+        );\r
+      break;\r
+    default:\r
+      SmmSetMemoryAttributes (\r
+        MemoryMap->PhysicalStart,\r
+        EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),\r
+        EFI_MEMORY_XP\r
+        );\r
+      break;\r
+    }\r
+    MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);\r
+  }\r
+\r
+  PatchSmmSaveStateMap ();\r
+  PatchGdtIdtMap ();\r
+\r
+  return ;\r
+}\r
index 329574ebb24ebcc155b2d6ceee8f35710b37504c..4b7fad29c30a0c65093917aacddd430c46f5613d 100644 (file)
@@ -29,11 +29,6 @@ UINTN                     mSmmProfileSize;
 //\r
 UINTN                     mMsrDsAreaSize   = SMM_PROFILE_DTS_SIZE;\r
 \r
-//\r
-// The flag indicates if execute-disable is supported by processor.\r
-//\r
-BOOLEAN                   mXdSupported     = TRUE;\r
-\r
 //\r
 // The flag indicates if execute-disable is enabled on processor.\r
 //\r
@@ -529,6 +524,12 @@ InitPaging (
         //\r
         continue;\r
       }\r
+      if ((*Pde & IA32_PG_PS) != 0) {\r
+        //\r
+        // This is 1G entry, skip it\r
+        //\r
+        continue;\r
+      }\r
       Pte = (UINT64 *)(UINTN)(*Pde & PHYSICAL_ADDRESS_MASK);\r
       if (Pte == 0) {\r
         continue;\r
@@ -587,6 +588,15 @@ InitPaging (
         //\r
         continue;\r
       }\r
+      if ((*Pde & IA32_PG_PS) != 0) {\r
+        //\r
+        // This is 1G entry, set NX bit and skip it\r
+        //\r
+        if (mXdSupported) {\r
+          *Pde = *Pde | IA32_PG_NX;\r
+        }\r
+        continue;\r
+      }\r
       Pte = (UINT64 *)(UINTN)(*Pde & PHYSICAL_ADDRESS_MASK);\r
       if (Pte == 0) {\r
         continue;\r
@@ -975,25 +985,6 @@ CheckFeatureSupported (
   }\r
 }\r
 \r
-/**\r
-  Enable XD feature.\r
-\r
-**/\r
-VOID\r
-ActivateXd (\r
-  VOID\r
-  )\r
-{\r
-  UINT64           MsrRegisters;\r
-\r
-  MsrRegisters = AsmReadMsr64 (MSR_EFER);\r
-  if ((MsrRegisters & MSR_EFER_XD) != 0) {\r
-    return ;\r
-  }\r
-  MsrRegisters |= MSR_EFER_XD;\r
-  AsmWriteMsr64 (MSR_EFER, MsrRegisters);\r
-}\r
-\r
 /**\r
   Enable single step.\r
 \r
index 13ff675ba29cbd3d0f591aaecb5a2731d713236a..b6fb5cf34b23e20d388e51bfa2c0a04bb7a44c85 100644 (file)
@@ -96,15 +96,6 @@ CheckFeatureSupported (
   VOID\r
   );\r
 \r
-/**\r
-  Enable XD feature.\r
-\r
-**/\r
-VOID\r
-ActivateXd (\r
-  VOID\r
-  );\r
-\r
 /**\r
   Update page table according to protected memory ranges and the 4KB-page mapped memory ranges.\r
 \r
@@ -114,7 +105,13 @@ InitPaging (
   VOID\r
   );\r
 \r
+//\r
+// The flag indicates if execute-disable is supported by processor.\r
+//\r
 extern BOOLEAN    mXdSupported;\r
+//\r
+// The flag indicates if execute-disable is enabled on processor.\r
+//\r
 extern BOOLEAN    mXdEnabled;\r
 \r
 #endif // _SMM_PROFILE_H_\r
index 9cee784156eb0338e647d62464591e6319bd6110..b3e50a4f20e119c57b0a9b2650664b72ec55754c 100644 (file)
@@ -18,6 +18,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define ACC_MAX_BIT                 BIT3\r
 LIST_ENTRY                          mPagePool = INITIALIZE_LIST_HEAD_VARIABLE (mPagePool);\r
 BOOLEAN                             m1GPageTableSupport = FALSE;\r
+UINT8                               mPhysicalAddressBits;\r
+BOOLEAN                             mCpuSmmStaticPageTable;\r
 \r
 /**\r
   Check if 1-GByte pages is supported by processor or not.\r
@@ -85,6 +87,146 @@ GetSubEntriesNum (
   return BitFieldRead64 (*Entry, 52, 60);\r
 }\r
 \r
+/**\r
+  Calculate the maximum support address.\r
+\r
+  @return the maximum support address.\r
+**/\r
+UINT8\r
+CalculateMaximumSupportAddress (\r
+  VOID\r
+  )\r
+{\r
+  UINT32                                        RegEax;\r
+  UINT8                                         PhysicalAddressBits;\r
+  VOID                                          *Hob;\r
+\r
+  //\r
+  // Get physical address bits supported.\r
+  //\r
+  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
+  if (Hob != NULL) {\r
+    PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
+  } else {\r
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+    if (RegEax >= 0x80000008) {\r
+      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+      PhysicalAddressBits = (UINT8) RegEax;\r
+    } else {\r
+      PhysicalAddressBits = 36;\r
+    }\r
+  }\r
+\r
+  //\r
+  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
+  //\r
+  ASSERT (PhysicalAddressBits <= 52);\r
+  if (PhysicalAddressBits > 48) {\r
+    PhysicalAddressBits = 48;\r
+  }\r
+  return PhysicalAddressBits;\r
+}\r
+\r
+/**\r
+  Set static page table.\r
+\r
+  @param[in] PageTable     Address of page table.\r
+**/\r
+VOID\r
+SetStaticPageTable (\r
+  IN UINTN               PageTable\r
+  )\r
+{\r
+  UINT64                                        PageAddress;\r
+  UINTN                                         NumberOfPml4EntriesNeeded;\r
+  UINTN                                         NumberOfPdpEntriesNeeded;\r
+  UINTN                                         IndexOfPml4Entries;\r
+  UINTN                                         IndexOfPdpEntries;\r
+  UINTN                                         IndexOfPageDirectoryEntries;\r
+  UINT64                                        *PageMapLevel4Entry;\r
+  UINT64                                        *PageMap;\r
+  UINT64                                        *PageDirectoryPointerEntry;\r
+  UINT64                                        *PageDirectory1GEntry;\r
+  UINT64                                        *PageDirectoryEntry;\r
+\r
+  if (mPhysicalAddressBits <= 39 ) {\r
+    NumberOfPml4EntriesNeeded = 1;\r
+    NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (mPhysicalAddressBits - 30));\r
+  } else {\r
+    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (mPhysicalAddressBits - 39));\r
+    NumberOfPdpEntriesNeeded = 512;\r
+  }\r
+\r
+  //\r
+  // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.\r
+  //\r
+  PageMap         = (VOID *) PageTable;\r
+\r
+  PageMapLevel4Entry = PageMap;\r
+  PageAddress        = 0;\r
+  for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {\r
+    //\r
+    // Each PML4 entry points to a page of Page Directory Pointer entries.\r
+    //\r
+    PageDirectoryPointerEntry = (UINT64 *) ((*PageMapLevel4Entry) & gPhyMask);\r
+    if (PageDirectoryPointerEntry == NULL) {\r
+      PageDirectoryPointerEntry = AllocatePageTableMemory (1);\r
+      ASSERT(PageDirectoryPointerEntry != NULL);\r
+      ZeroMem (PageDirectoryPointerEntry, EFI_PAGES_TO_SIZE(1));\r
+\r
+      *PageMapLevel4Entry = ((UINTN)PageDirectoryPointerEntry & gPhyMask)  | PAGE_ATTRIBUTE_BITS;\r
+    }\r
+\r
+    if (m1GPageTableSupport) {\r
+      PageDirectory1GEntry = PageDirectoryPointerEntry;\r
+      for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {\r
+        if (IndexOfPml4Entries == 0 && IndexOfPageDirectoryEntries < 4) {\r
+          //\r
+          // Skip the < 4G entries\r
+          //\r
+          continue;\r
+        }\r
+        //\r
+        // Fill in the Page Directory entries\r
+        //\r
+        *PageDirectory1GEntry = (PageAddress & gPhyMask) | IA32_PG_PS | PAGE_ATTRIBUTE_BITS;\r
+      }\r
+    } else {\r
+      PageAddress = BASE_4GB;\r
+      for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
+        if (IndexOfPml4Entries == 0 && IndexOfPdpEntries < 4) {\r
+          //\r
+          // Skip the < 4G entries\r
+          //\r
+          continue;\r
+        }\r
+        //\r
+        // Each Directory Pointer entries points to a page of Page Directory entires.\r
+        // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.\r
+        //\r
+        PageDirectoryEntry = (UINT64 *) ((*PageDirectoryPointerEntry) & gPhyMask);\r
+        if (PageDirectoryEntry == NULL) {\r
+          PageDirectoryEntry = AllocatePageTableMemory (1);\r
+          ASSERT(PageDirectoryEntry != NULL);\r
+          ZeroMem (PageDirectoryEntry, EFI_PAGES_TO_SIZE(1));\r
+\r
+          //\r
+          // Fill in a Page Directory Pointer Entries\r
+          //\r
+          *PageDirectoryPointerEntry = (UINT64)(UINTN)PageDirectoryEntry | PAGE_ATTRIBUTE_BITS;\r
+        }\r
+\r
+        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {\r
+          //\r
+          // Fill in the Page Directory entries\r
+          //\r
+          *PageDirectoryEntry = (UINT64)PageAddress | IA32_PG_PS | PAGE_ATTRIBUTE_BITS;\r
+        }\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
 /**\r
   Create PageTable for SMM use.\r
 \r
@@ -108,11 +250,17 @@ SmmInitPageTable (
   //\r
   InitializeSpinLock (mPFLock);\r
 \r
+  mCpuSmmStaticPageTable = PcdGetBool (PcdCpuSmmStaticPageTable);\r
   m1GPageTableSupport = Is1GPageSupport ();\r
+  DEBUG ((DEBUG_INFO, "1GPageTableSupport - 0x%x\n", m1GPageTableSupport));\r
+  DEBUG ((DEBUG_INFO, "PcdCpuSmmStaticPageTable - 0x%x\n", mCpuSmmStaticPageTable));\r
+\r
+  mPhysicalAddressBits = CalculateMaximumSupportAddress ();\r
+  DEBUG ((DEBUG_INFO, "PhysicalAddressBits - 0x%x\n", mPhysicalAddressBits));\r
   //\r
   // Generate PAE page table for the first 4GB memory space\r
   //\r
-  Pages = Gen4GPageTable (PAGE_TABLE_PAGES + 1, FALSE);\r
+  Pages = Gen4GPageTable (FALSE);\r
 \r
   //\r
   // Set IA32_PG_PMNT bit to mask this entry\r
@@ -125,21 +273,28 @@ SmmInitPageTable (
   //\r
   // Fill Page-Table-Level4 (PML4) entry\r
   //\r
-  PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (PAGE_TABLE_PAGES + 1));\r
-  *PTEntry = Pages + PAGE_ATTRIBUTE_BITS;\r
+  PTEntry = (UINT64*)AllocatePageTableMemory (1);\r
+  ASSERT (PTEntry != NULL);\r
+  *PTEntry = Pages | PAGE_ATTRIBUTE_BITS;\r
   ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry));\r
+\r
   //\r
   // Set sub-entries number\r
   //\r
   SetSubEntriesNum (PTEntry, 3);\r
 \r
-  //\r
-  // Add remaining pages to page pool\r
-  //\r
-  FreePage = (LIST_ENTRY*)(PTEntry + EFI_PAGE_SIZE / sizeof (*PTEntry));\r
-  while ((UINTN)FreePage < Pages) {\r
-    InsertTailList (&mPagePool, FreePage);\r
-    FreePage += EFI_PAGE_SIZE / sizeof (*FreePage);\r
+  if (mCpuSmmStaticPageTable) {\r
+    SetStaticPageTable ((UINTN)PTEntry);\r
+  } else {\r
+    //\r
+    // Add pages to page pool\r
+    //\r
+    FreePage = (LIST_ENTRY*)AllocatePageTableMemory (PAGE_TABLE_PAGES);\r
+    ASSERT (FreePage != NULL);\r
+    for (Index = 0; Index < PAGE_TABLE_PAGES; Index++) {\r
+      InsertTailList (&mPagePool, FreePage);\r
+      FreePage += EFI_PAGE_SIZE / sizeof (*FreePage);\r
+    }\r
   }\r
 \r
   if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
@@ -561,7 +716,7 @@ SmiDefaultPFHandler (
     break;\r
   case SmmPageSize1G:\r
     if (!m1GPageTableSupport) {\r
-      DEBUG ((EFI_D_ERROR, "1-GByte pages is not supported!"));\r
+      DEBUG ((DEBUG_ERROR, "1-GByte pages is not supported!"));\r
       ASSERT (FALSE);\r
     }\r
     //\r
@@ -612,8 +767,8 @@ SmiDefaultPFHandler (
       // Check if the entry has already existed, this issue may occur when the different\r
       // size page entries created under the same entry\r
       //\r
-      DEBUG ((EFI_D_ERROR, "PageTable = %lx, PTIndex = %x, PageTable[PTIndex] = %lx\n", PageTable, PTIndex, PageTable[PTIndex]));\r
-      DEBUG ((EFI_D_ERROR, "New page table overlapped with old page table!\n"));\r
+      DEBUG ((DEBUG_ERROR, "PageTable = %lx, PTIndex = %x, PageTable[PTIndex] = %lx\n", PageTable, PTIndex, PageTable[PTIndex]));\r
+      DEBUG ((DEBUG_ERROR, "New page table overlapped with old page table!\n"));\r
       ASSERT (FALSE);\r
     }\r
     //\r
@@ -654,13 +809,18 @@ SmiPFHandler (
 \r
   PFAddress = AsmReadCr2 ();\r
 \r
+  if (mCpuSmmStaticPageTable && (PFAddress >= LShiftU64 (1, (mPhysicalAddressBits - 1)))) {\r
+    DEBUG ((DEBUG_ERROR, "Do not support address 0x%lx by processor!\n", PFAddress));\r
+    CpuDeadLoop ();\r
+  }\r
+\r
   //\r
   // If a page fault occurs in SMRAM range, it should be in a SMM stack guard page.\r
   //\r
   if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&\r
       (PFAddress >= mCpuHotPlugData.SmrrBase) &&\r
       (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {\r
-    DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));\r
+    DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));\r
     CpuDeadLoop ();\r
   }\r
 \r
@@ -670,7 +830,7 @@ SmiPFHandler (
   if ((PFAddress < mCpuHotPlugData.SmrrBase) ||\r
       (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
     if ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0) {\r
-      DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%lx) out of SMM range after SMM is locked!\n", PFAddress));\r
+      DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%lx) out of SMM range after SMM is locked!\n", PFAddress));\r
       DEBUG_CODE (\r
         DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp);\r
       );\r
@@ -689,3 +849,87 @@ SmiPFHandler (
 \r
   ReleaseSpinLock (mPFLock);\r
 }\r
+\r
+/**\r
+  This function sets memory attribute for page table.\r
+**/\r
+VOID\r
+SetPageTableAttributes (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                 Index2;\r
+  UINTN                 Index3;\r
+  UINTN                 Index4;\r
+  UINT64                *L1PageTable;\r
+  UINT64                *L2PageTable;\r
+  UINT64                *L3PageTable;\r
+  UINT64                *L4PageTable;\r
+  BOOLEAN               IsSplitted;\r
+  BOOLEAN               PageTableSplitted;\r
+\r
+  if (!mCpuSmmStaticPageTable) {\r
+    return ;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));\r
+\r
+  //\r
+  // Disable write protection, because we need mark page table to be write protected.\r
+  // We need *write* page table memory, to mark itself to be *read only*.\r
+  //\r
+  AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);\r
+\r
+  do {\r
+    DEBUG ((DEBUG_INFO, "Start...\n"));\r
+    PageTableSplitted = FALSE;\r
+\r
+    L4PageTable = (UINT64 *)GetPageTableBase ();\r
+    SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L4PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+    PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+\r
+    for (Index4 = 0; Index4 < SIZE_4KB/sizeof(UINT64); Index4++) {\r
+      L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);\r
+      if (L3PageTable == NULL) {\r
+        continue;\r
+      }\r
+\r
+      SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+      PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+\r
+      for (Index3 = 0; Index3 < SIZE_4KB/sizeof(UINT64); Index3++) {\r
+        if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {\r
+          // 1G\r
+          continue;\r
+        }\r
+        L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);\r
+        if (L2PageTable == NULL) {\r
+          continue;\r
+        }\r
+\r
+        SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+        PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+\r
+        for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {\r
+          if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
+            // 2M\r
+            continue;\r
+          }\r
+          L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);\r
+          if (L1PageTable == NULL) {\r
+            continue;\r
+          }\r
+          SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+          PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+        }\r
+      }\r
+    }\r
+  } while (PageTableSplitted);\r
+\r
+  //\r
+  // Enable write protection, after page table updated.\r
+  //\r
+  AsmWriteCr0 (AsmReadCr0() | CR0_WP);\r
+\r
+  return ;\r
+}\r
index 7e9ac58cb2c96f33b554654b40e23c624522a72c..f4761b01608c3710e42706361869a60f83056706 100644 (file)
@@ -1,6 +1,6 @@
 #------------------------------------------------------------------------------\r
 #\r
-# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 # This program and the accompanying materials\r
 # are licensed and made available under the terms and conditions of the BSD License\r
 # which accompanies this distribution.  The full text of the license may be found at\r
@@ -24,8 +24,13 @@ ASM_GLOBAL  ASM_PFX(gcSmiHandlerSize)
 ASM_GLOBAL  ASM_PFX(gSmiCr3)\r
 ASM_GLOBAL  ASM_PFX(gSmiStack)\r
 ASM_GLOBAL  ASM_PFX(gSmbase)\r
+ASM_GLOBAL  ASM_PFX(mXdSupported)\r
 ASM_GLOBAL  ASM_PFX(gSmiHandlerIdtr)\r
 \r
+.equ            MSR_IA32_MISC_ENABLE, 0x1A0\r
+.equ            MSR_EFER, 0xc0000080\r
+.equ            MSR_EFER_XD, 0x800\r
+\r
 #\r
 # Constants relating to PROCESSOR_SMM_DESCRIPTOR\r
 #\r
@@ -132,6 +137,32 @@ ASM_PFX(gSmiCr3):    .space  4
     movl    $TSS_SEGMENT, %eax\r
     ltr     %ax\r
 \r
+# enable NXE if supported\r
+    .byte   0xb0                        # mov al, imm8\r
+ASM_PFX(mXdSupported): .byte 1\r
+    cmpb    $0, %al\r
+    jz      SkipNxe\r
+#\r
+# Check XD disable bit\r
+#\r
+    movl    $MSR_IA32_MISC_ENABLE, %ecx\r
+    rdmsr\r
+    subl    $4, %esp\r
+    pushq   %rdx                       # save MSR_IA32_MISC_ENABLE[63-32]\r
+    testl   $BIT2, %edx                # MSR_IA32_MISC_ENABLE[34]\r
+    jz      L13\r
+    andw    $0x0FFFB, %dx              # clear XD Disable bit if it is set\r
+    wrmsr\r
+L13:\r
+    movl    $MSR_EFER, %ecx\r
+    rdmsr\r
+    orw     $MSR_EFER_XD,%ax            # enable NXE\r
+    wrmsr\r
+    jmp     @NxeDone\r
+SkipNxe:\r
+    subl    $8, %esp\r
+NxeDone:\r
+\r
     #\r
     # Switch to LongMode\r
     #\r
@@ -139,12 +170,13 @@ ASM_PFX(gSmiCr3):    .space  4
     call     Base                         # push return address for retf later\r
 Base:\r
     addl    $(LongMode - Base), (%rsp)  # offset for far retf, seg is the 1st arg\r
-    movl    $0xc0000080, %ecx\r
+\r
+    movl    $MSR_EFER, %ecx\r
     rdmsr\r
-    orb     $1,%ah\r
+    orb     $1,%ah                      # enable LME\r
     wrmsr\r
     movq    %cr0, %rbx\r
-    orl     $0x080010000, %ebx          # enable paging + WP\r
+    orl     $0x080010023, %ebx          # enable paging + WP + NE + MP + PE\r
     movq    %rbx, %cr0\r
     retf\r
 LongMode:                               # long mode (64-bit code) starts here\r
@@ -162,10 +194,10 @@ LongMode:                               # long mode (64-bit code) starts here
 #   jmp     _SmiHandler                 ; instruction is not needed\r
 \r
 _SmiHandler:\r
-    movq    (%rsp), %rbx\r
+    movq    8(%rsp), %rbx\r
     # Save FP registers\r
 \r
-    subq    $0x208, %rsp\r
+    subq    $0x200, %rsp\r
     .byte   0x48                        # FXSAVE64\r
     fxsave  (%rsp)\r
 \r
@@ -191,6 +223,21 @@ _SmiHandler:
     .byte   0x48                        # FXRSTOR64\r
     fxrstor (%rsp)\r
 \r
+    addq    $0x200, %rsp\r
+\r
+    movabsq $ASM_PFX(mXdSupported), %rax\r
+    movb    (%rax), %al\r
+    cmpb    $0, %al\r
+    jz      L16\r
+    popq    %rdx                        # get saved MSR_IA32_MISC_ENABLE[63-32]\r
+    testl   $BIT2, %edx\r
+    jz      L16\r
+    movl    $MSR_IA32_MISC_ENABLE, %ecx\r
+    rdmsr\r
+    orw     $BIT2, %dx                  # set XD Disable bit if it was set before entering into SMM\r
+    wrmsr\r
+\r
+L16:\r
     rsm\r
 \r
 ASM_PFX(gcSmiHandlerSize):    .word      . - _SmiEntryPoint\r
index 094cf2c3da330820ef9056c57ff78aaf0cbfa6f4..e2fcb6f0d590db487443844e792bc323f8c753de 100644 (file)
@@ -1,5 +1,5 @@
 ;------------------------------------------------------------------------------ ;\r
-; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 ; This program and the accompanying materials\r
 ; are licensed and made available under the terms and conditions of the BSD License\r
 ; which accompanies this distribution.  The full text of the license may be found at\r
@@ -29,8 +29,12 @@ EXTERNDEF   gcSmiHandlerSize:WORD
 EXTERNDEF   gSmiCr3:DWORD\r
 EXTERNDEF   gSmiStack:DWORD\r
 EXTERNDEF   gSmbase:DWORD\r
+EXTERNDEF   mXdSupported:BYTE\r
 EXTERNDEF   gSmiHandlerIdtr:FWORD\r
 \r
+MSR_IA32_MISC_ENABLE  EQU     1A0h\r
+MSR_EFER      EQU     0c0000080h\r
+MSR_EFER_XD   EQU     0800h\r
 \r
 ;\r
 ; Constants relating to PROCESSOR_SMM_DESCRIPTOR\r
@@ -130,17 +134,44 @@ gSmiCr3     DD      ?
     mov     eax, TSS_SEGMENT\r
     ltr     ax\r
 \r
+; enable NXE if supported\r
+    DB      0b0h                        ; mov al, imm8\r
+mXdSupported     DB      1\r
+    cmp     al, 0\r
+    jz      @SkipXd\r
+;\r
+; Check XD disable bit\r
+;\r
+    mov     ecx, MSR_IA32_MISC_ENABLE\r
+    rdmsr\r
+    sub     esp, 4\r
+    push    rdx                        ; save MSR_IA32_MISC_ENABLE[63-32]\r
+    test    edx, BIT2                  ; MSR_IA32_MISC_ENABLE[34]\r
+    jz      @f\r
+    and     dx, 0FFFBh                 ; clear XD Disable bit if it is set\r
+    wrmsr\r
+@@:\r
+    mov     ecx, MSR_EFER\r
+    rdmsr\r
+    or      ax, MSR_EFER_XD            ; enable NXE\r
+    wrmsr\r
+    jmp     @XdDone\r
+@SkipXd:\r
+    sub     esp, 8\r
+@XdDone:\r
+\r
 ; Switch into @LongMode\r
     push    LONG_MODE_CS                ; push cs hardcore here\r
     call    Base                       ; push return address for retf later\r
 Base:\r
     add     dword ptr [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg\r
-    mov     ecx, 0c0000080h\r
+\r
+    mov     ecx, MSR_EFER\r
     rdmsr\r
-    or      ah, 1\r
+    or      ah, 1                      ; enable LME\r
     wrmsr\r
     mov     rbx, cr0\r
-    or      ebx, 080010000h            ; enable paging + WP\r
+    or      ebx, 080010023h            ; enable paging + WP + NE + MP + PE\r
     mov     cr0, rbx\r
     retf\r
 @LongMode:                              ; long mode (64-bit code) starts here\r
@@ -163,7 +194,7 @@ _SmiHandler:
     ;\r
     ; Save FP registers\r
     ;\r
-    sub     rsp, 208h\r
+    sub     rsp, 200h\r
     DB      48h                         ; FXSAVE64\r
     fxsave  [rsp]\r
 \r
@@ -172,15 +203,15 @@ _SmiHandler:
     mov     rcx, rbx\r
     mov     rax, CpuSmmDebugEntry\r
     call    rax\r
-    \r
+\r
     mov     rcx, rbx\r
     mov     rax, SmiRendezvous          ; rax <- absolute addr of SmiRedezvous\r
     call    rax\r
-    \r
+\r
     mov     rcx, rbx\r
     mov     rax, CpuSmmDebugExit\r
     call    rax\r
-    \r
+\r
     add     rsp, 20h\r
 \r
     ;\r
@@ -189,6 +220,21 @@ _SmiHandler:
     DB      48h                         ; FXRSTOR64\r
     fxrstor [rsp]\r
 \r
+    add     rsp, 200h\r
+\r
+    mov     rax, ASM_PFX(mXdSupported)\r
+    mov     al, [rax]\r
+    cmp     al, 0\r
+    jz      @f\r
+    pop     rdx                       ; get saved MSR_IA32_MISC_ENABLE[63-32]\r
+    test    edx, BIT2\r
+    jz      @f\r
+    mov     ecx, MSR_IA32_MISC_ENABLE\r
+    rdmsr\r
+    or      dx, BIT2                  ; set XD Disable bit if it was set before entering into SMM\r
+    wrmsr\r
+\r
+@@:\r
     rsm\r
 \r
 gcSmiHandlerSize    DW      $ - _SmiEntryPoint\r
index b717cda2c93ecf23286aa58c369faf80b71ff599..c3c094ff9f7e9882807e71038280b3b801c63c4c 100644 (file)
 ; Variables referrenced by C code\r
 ;\r
 \r
+%define MSR_IA32_MISC_ENABLE 0x1A0\r
+%define MSR_EFER      0xc0000080\r
+%define MSR_EFER_XD   0x800\r
+\r
 ;\r
 ; Constants relating to PROCESSOR_SMM_DESCRIPTOR\r
 ;\r
@@ -50,6 +54,7 @@ extern ASM_PFX(CpuSmmDebugEntry)
 extern ASM_PFX(CpuSmmDebugExit)\r
 \r
 global ASM_PFX(gSmbase)\r
+global ASM_PFX(mXdSupported)\r
 global ASM_PFX(gSmiStack)\r
 global ASM_PFX(gSmiCr3)\r
 global ASM_PFX(gcSmiHandlerTemplate)\r
@@ -69,7 +74,7 @@ _SmiEntryPoint:
     mov     [cs:bx + 2], eax\r
 o32 lgdt    [cs:bx]                       ; lgdt fword ptr cs:[bx]\r
     mov     ax, PROTECT_MODE_CS\r
-    mov     [cs:bx-0x2],ax    \r
+    mov     [cs:bx-0x2],ax\r
     DB      0x66, 0xbf                   ; mov edi, SMBASE\r
 ASM_PFX(gSmbase): DD 0\r
     lea     eax, [edi + (@ProtectedMode - _SmiEntryPoint) + 0x8000]\r
@@ -79,7 +84,7 @@ ASM_PFX(gSmbase): DD 0
     or      ebx, 0x23\r
     mov     cr0, ebx\r
     jmp     dword 0x0:0x0\r
-_GdtDesc:   \r
+_GdtDesc:\r
     DW 0\r
     DD 0\r
 \r
@@ -112,17 +117,44 @@ ASM_PFX(gSmiCr3): DD 0
     mov     eax, TSS_SEGMENT\r
     ltr     ax\r
 \r
+; enable NXE if supported\r
+    DB      0xb0                        ; mov al, imm8\r
+ASM_PFX(mXdSupported):     DB      1\r
+    cmp     al, 0\r
+    jz      @SkipXd\r
+;\r
+; Check XD disable bit\r
+;\r
+    mov     ecx, MSR_IA32_MISC_ENABLE\r
+    rdmsr\r
+    sub     esp, 4\r
+    push    rdx                        ; save MSR_IA32_MISC_ENABLE[63-32]\r
+    test    edx, BIT2                  ; MSR_IA32_MISC_ENABLE[34]\r
+    jz      .0\r
+    and     dx, 0xFFFB                 ; clear XD Disable bit if it is set\r
+    wrmsr\r
+.0:\r
+    mov     ecx, MSR_EFER\r
+    rdmsr\r
+    or      ax, MSR_EFER_XD            ; enable NXE\r
+    wrmsr\r
+    jmp     @XdDone\r
+@SkipXd:\r
+    sub     esp, 8\r
+@XdDone:\r
+\r
 ; Switch into @LongMode\r
     push    LONG_MODE_CS                ; push cs hardcore here\r
-    call    Base                       ; push reture address for retf later\r
+    call    Base                       ; push return address for retf later\r
 Base:\r
     add     dword [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg\r
-    mov     ecx, 0xc0000080\r
+\r
+    mov     ecx, MSR_EFER\r
     rdmsr\r
-    or      ah, 1\r
+    or      ah, 1                      ; enable LME\r
     wrmsr\r
     mov     rbx, cr0\r
-    or      ebx, 080010000h            ; enable paging + WP\r
+    or      ebx, 0x80010023            ; enable paging + WP + NE + MP + PE\r
     mov     cr0, rbx\r
     retf\r
 @LongMode:                              ; long mode (64-bit code) starts here\r
@@ -140,12 +172,12 @@ Base:
 ;   jmp     _SmiHandler                 ; instruction is not needed\r
 \r
 _SmiHandler:\r
-    mov     rbx, [rsp]                  ; rbx <- CpuIndex\r
+    mov     rbx, [rsp + 0x8]             ; rcx <- CpuIndex\r
 \r
     ;\r
     ; Save FP registers\r
     ;\r
-    sub     rsp, 0x208\r
+    sub     rsp, 0x200\r
     DB      0x48                         ; FXSAVE64\r
     fxsave  [rsp]\r
 \r
@@ -154,15 +186,15 @@ _SmiHandler:
     mov     rcx, rbx\r
     mov     rax, CpuSmmDebugEntry\r
     call    rax\r
-    \r
+\r
     mov     rcx, rbx\r
     mov     rax, SmiRendezvous          ; rax <- absolute addr of SmiRedezvous\r
     call    rax\r
-    \r
+\r
     mov     rcx, rbx\r
     mov     rax, CpuSmmDebugExit\r
     call    rax\r
-    \r
+\r
     add     rsp, 0x20\r
 \r
     ;\r
@@ -171,6 +203,21 @@ _SmiHandler:
     DB      0x48                         ; FXRSTOR64\r
     fxrstor [rsp]\r
 \r
+    add     rsp, 0x200\r
+\r
+    mov     rax, ASM_PFX(mXdSupported)\r
+    mov     al, [rax]\r
+    cmp     al, 0\r
+    jz      .1\r
+    pop     rdx                       ; get saved MSR_IA32_MISC_ENABLE[63-32]\r
+    test    edx, BIT2\r
+    jz      .1\r
+    mov     ecx, MSR_IA32_MISC_ENABLE\r
+    rdmsr\r
+    or      dx, BIT2                  ; set XD Disable bit if it was set before entering into SMM\r
+    wrmsr\r
+\r
+.1:\r
     rsm\r
 \r
 gcSmiHandlerSize    DW      $ - _SmiEntryPoint\r
index 2ae6f2c32f54853983af85dacd6bc0b6a2b81a9a..2e2792db20e520b4ab8f30a1f86fbddda2e7bb7a 100644 (file)
@@ -1,6 +1,6 @@
 #------------------------------------------------------------------------------\r
 #\r
-# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 # This program and the accompanying materials\r
 # are licensed and made available under the terms and conditions of the BSD License\r
 # which accompanies this distribution.  The full text of the license may be found at\r
@@ -128,244 +128,8 @@ ASM_PFX(gcSmiGdtr):
     .quad      NullSeg\r
 \r
 ASM_PFX(gcSmiIdtr):\r
-    .word      IDT_SIZE - 1\r
-    .quad      _SmiIDT\r
-\r
-\r
-#\r
-# Here is the IDT. There are 32 (not 255) entries in it since only processor\r
-# generated exceptions will be handled.\r
-#\r
-_SmiIDT:\r
-# The following segment repeats 32 times:\r
-# No. 1\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 2\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 3\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 4\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 5\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 6\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 7\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 8\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 9\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 10\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 11\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 12\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 13\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 14\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 15\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 16\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 17\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 18\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 19\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 20\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 21\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 22\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 23\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 24\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 25\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 26\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 27\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 28\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 29\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 30\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 31\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-# No. 32\r
-    .word 0                             # Offset 0:15\r
-    .word CODE_SEL\r
-    .byte 0                             # Unused\r
-    .byte 0x8e                          # Interrupt Gate, Present\r
-    .word 0                             # Offset 16:31\r
-    .quad 0                             # Offset 32:63\r
-\r
-_SmiIDTEnd:\r
-\r
-.equ  IDT_SIZE, (_SmiIDTEnd - _SmiIDT)\r
+    .word      0\r
+    .quad      0\r
 \r
     .text\r
 \r
@@ -600,11 +364,3 @@ L5:
     addq    $16, %rsp                    # skip INT# & ErrCode\r
     iretq\r
 \r
-ASM_GLOBAL ASM_PFX(InitializeIDTSmmStackGuard)\r
-ASM_PFX(InitializeIDTSmmStackGuard):\r
-# If SMM Stack Guard feature is enabled, set the IST field of\r
-# the interrupt gate for Page Fault Exception to be 1\r
-#\r
-    movabsq  $_SmiIDT + 14 * 16, %rax\r
-    movb     $1, 4(%rax)\r
-    ret\r
index ab716450b71a624eeb0f742e224de472170e258b..f55ba723ff3878e698b43b157e6036999ffd6eec 100644 (file)
@@ -1,5 +1,5 @@
 ;------------------------------------------------------------------------------ ;\r
-; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 ; This program and the accompanying materials\r
 ; are licensed and made available under the terms and conditions of the BSD License\r
 ; which accompanies this distribution.  The full text of the license may be found at\r
@@ -144,27 +144,8 @@ gcSmiGdtr   LABEL   FWORD
     DQ      offset NullSeg\r
 \r
 gcSmiIdtr   LABEL   FWORD\r
-    DW      IDT_SIZE - 1\r
-    DQ      offset _SmiIDT\r
-\r
-    .data\r
-\r
-;\r
-; Here is the IDT. There are 32 (not 255) entries in it since only processor\r
-; generated exceptions will be handled.\r
-;\r
-_SmiIDT:\r
-REPEAT      32\r
-    DW      0                           ; Offset 0:15\r
-    DW      CODE_SEL                    ; Segment selector\r
-    DB      0                           ; Unused\r
-    DB      8eh                         ; Interrupt Gate, Present\r
-    DW      0                           ; Offset 16:31\r
-    DQ      0                           ; Offset 32:63\r
-            ENDM\r
-_SmiIDTEnd:\r
-\r
-IDT_SIZE = (offset _SmiIDTEnd - offset _SmiIDT)\r
+    DW      0\r
+    DQ      0\r
 \r
     .code\r
 \r
@@ -400,14 +381,4 @@ PageFaultIdtHandlerSmmProfile    PROC
     iretq\r
 PageFaultIdtHandlerSmmProfile ENDP\r
 \r
-InitializeIDTSmmStackGuard   PROC\r
-;\r
-; If SMM Stack Guard feature is enabled, set the IST field of\r
-; the interrupt gate for Page Fault Exception to be 1\r
-;\r
-    lea     rax, _SmiIDT + 14 * 16\r
-    mov     byte ptr [rax + 4], 1\r
-    ret\r
-InitializeIDTSmmStackGuard   ENDP\r
-\r
     END\r
index 821ee182b6f94c74de6a951bfb25db49577ccfd9..bc8d95d8dc99e6edaa5aea563921d887e844174c 100644 (file)
@@ -145,25 +145,8 @@ ASM_PFX(gcSmiGdtr):
     DQ        NullSeg\r
 \r
 ASM_PFX(gcSmiIdtr):\r
-    DW      IDT_SIZE - 1\r
-    DQ        _SmiIDT\r
-\r
-;\r
-; Here is the IDT. There are 32 (not 255) entries in it since only processor\r
-; generated exceptions will be handled.\r
-;\r
-_SmiIDT:\r
-%rep 32\r
-    DW      0                           ;   0:15\r
-    DW      CODE_SEL                    ; Segment selector\r
-    DB      0                           ; Unused\r
-    DB      0x8e                         ; Interrupt Gate, Present\r
-    DW      0                           ;   16:31\r
-    DQ      0                           ;   32:63\r
-%endrep\r
-_SmiIDTEnd:\r
-\r
-IDT_SIZE equ  _SmiIDTEnd -   _SmiIDT\r
+    DW      0\r
+    DQ      0\r
 \r
     DEFAULT REL\r
     SECTION .text\r
@@ -400,13 +383,3 @@ ASM_PFX(PageFaultIdtHandlerSmmProfile):
     add     rsp, 16           ; skip INT# & ErrCode\r
     iretq\r
 \r
-global ASM_PFX(InitializeIDTSmmStackGuard)\r
-ASM_PFX(InitializeIDTSmmStackGuard):\r
-;\r
-; If SMM Stack Guard feature is enabled, set the IST field of\r
-; the interrupt gate for Page Fault Exception to be 1\r
-;\r
-    lea     rax, [_SmiIDT + 14 * 16]\r
-    mov     byte [rax + 4], 1\r
-    ret\r
-\r
index 6844c3fc499d810bb041a38ae04084f934f090e7..d6d6a1a5035ca07c1d82175c427196a061062a8f 100644 (file)
@@ -14,6 +14,30 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "PiSmmCpuDxeSmm.h"\r
 \r
+EFI_PHYSICAL_ADDRESS                mGdtBuffer;\r
+UINTN                               mGdtBufferSize;\r
+\r
+/**\r
+  Initialize IDT for SMM Stack Guard.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+InitializeIDTSmmStackGuard (\r
+  VOID\r
+  )\r
+{\r
+  IA32_IDT_GATE_DESCRIPTOR  *IdtGate;\r
+\r
+  //\r
+  // If SMM Stack Guard feature is enabled, set the IST field of\r
+  // the interrupt gate for Page Fault Exception to be 1\r
+  //\r
+  IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;\r
+  IdtGate += EXCEPT_IA32_PAGE_FAULT;\r
+  IdtGate->Bits.Reserved_0 = 1;\r
+}\r
+\r
 /**\r
   Initialize Gdt for all processors.\r
   \r
@@ -41,8 +65,10 @@ InitGdt (
   // on each SMI entry.\r
   //\r
   GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned\r
-  GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));\r
+  mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
+  GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));\r
   ASSERT (GdtTssTables != NULL);\r
+  mGdtBuffer = (UINTN)GdtTssTables;\r
   GdtTableStepSize = GdtTssTableSize;\r
 \r
   for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {\r
index 065fb2c24c7dcf02322b900e123518776a8caaa0..cc393dcd894e126b3666f56058487c45415b17ec 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 X64 processor specific functions to enable SMM profile.\r
 \r
-Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -45,12 +45,13 @@ InitSmmS3Cr3 (
   //\r
   // Generate PAE page table for the first 4GB memory space\r
   //\r
-  Pages = Gen4GPageTable (1, FALSE);\r
+  Pages = Gen4GPageTable (FALSE);\r
 \r
   //\r
   // Fill Page-Table-Level4 (PML4) entry\r
   //\r
-  PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (1));\r
+  PTEntry = (UINT64*)AllocatePageTableMemory (1);\r
+  ASSERT (PTEntry != NULL);\r
   *PTEntry = Pages | PAGE_ATTRIBUTE_BITS;\r
   ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry));\r
 \r