| ;------------------------------------------------------------------------------ | |
| ; | |
| ; Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR> | |
| ; SPDX-License-Identifier: BSD-2-Clause-Patent | |
| ; | |
| ; Abstract: | |
| ; | |
| ; Switch the stack from temporary memory to permanent memory. | |
| ; | |
| ;------------------------------------------------------------------------------ | |
| SECTION .text | |
| extern ASM_PFX(SwapStack) | |
| extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable)) | |
| ; Page table related bits in CR0/CR4/EFER | |
| %define CR0_PG_MASK 0x80010000 ; CR0.PG and CR0.WP | |
| %define CR4_PG_MASK 0x10B0 ; CR4.PSE, CR4.PAE, CR4.PGE and CR4.LA57 | |
| %define EFER_PG_MASK 0x800 ; EFER.NXE | |
| ;------------------------------------------------------------------------------ | |
| ; UINT32 | |
| ; EFIAPI | |
| ; Pei2LoaderSwitchStack ( | |
| ; VOID | |
| ; ) | |
| ;------------------------------------------------------------------------------ | |
| global ASM_PFX(Pei2LoaderSwitchStack) | |
| ASM_PFX(Pei2LoaderSwitchStack): | |
| xor eax, eax | |
| jmp ASM_PFX(FspSwitchStack) | |
| ;------------------------------------------------------------------------------ | |
| ; UINT32 | |
| ; EFIAPI | |
| ; Loader2PeiSwitchStack ( | |
| ; VOID | |
| ; ) | |
| ;------------------------------------------------------------------------------ | |
| global ASM_PFX(Loader2PeiSwitchStack) | |
| ASM_PFX(Loader2PeiSwitchStack): | |
| jmp ASM_PFX(FspSwitchStack) | |
| ;------------------------------------------------------------------------------ | |
| ; UINT32 | |
| ; EFIAPI | |
| ; FspSwitchStack ( | |
| ; VOID | |
| ; ) | |
| ;------------------------------------------------------------------------------ | |
| global ASM_PFX(FspSwitchStack) | |
| ASM_PFX(FspSwitchStack): | |
| ; Save current contexts | |
| push eax | |
| pushfd | |
| cli | |
| pushad | |
| ; | |
| ; Allocate 4x4 bytes on the stack. | |
| ; | |
| sub esp, 16 | |
| cmp byte [dword ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))], 0 | |
| jz SkipPagetableSave | |
| add esp, 16 | |
| ; Save EFER MSR lower 32 bits | |
| push ecx | |
| push eax | |
| mov ecx, 0xC0000080 | |
| rdmsr | |
| mov edx, eax | |
| pop eax | |
| pop ecx | |
| push edx | |
| ; Save CR registers | |
| mov eax, cr4 | |
| push eax | |
| mov eax, cr3 | |
| push eax | |
| mov eax, cr0 | |
| push eax | |
| SkipPagetableSave: | |
| sub esp, 8 | |
| sidt [esp] | |
| ; Load new stack | |
| push esp | |
| call ASM_PFX(SwapStack) | |
| mov esp, eax | |
| ; Restore previous contexts | |
| lidt [esp] | |
| add esp, 8 | |
| cmp byte [dword ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))], 0 | |
| jz SkipPagetableRestore | |
| ; [esp] stores new cr0 | |
| ; [esp+4] stores new cr3 | |
| ; [esp+8] stores new cr4 | |
| ; [esp+12] stores new Efer | |
| ; | |
| ; When new EFER.NXE == 1, the restore flow is: EFER --> CRx | |
| ; Otherwise: CRx --> EFER | |
| ; When new CR0.PG == 1, the restore flow for CRx is: CR3 --> CR4 --> CR0 | |
| ; Otherwise, the restore flow is: CR0 --> CR3 --> CR4 | |
| ; | |
| ; If NXE bit is changed to 1, change NXE before CR register | |
| ; This is because Nx bit in page table entry in new CR3 will be invalid | |
| ; if updating CR3 before EFER MSR. | |
| ; | |
| mov eax, [esp+12] | |
| bt eax, 11 | |
| jnc SkipEferLabel1 | |
| ; Restore EFER MSR | |
| mov ecx, 0xC0000080 | |
| rdmsr | |
| and eax, ~EFER_PG_MASK | |
| mov ebx, [esp+12] | |
| and ebx, EFER_PG_MASK | |
| or eax, ebx | |
| wrmsr | |
| SkipEferLabel1: | |
| ; | |
| ; if new cr0 is to disable page table, change CR0 before CR3/CR4 | |
| ; | |
| mov eax, [esp] | |
| bt eax, 31 | |
| jc SkipCr0Label1 | |
| ; Restore CR0 | |
| mov edx, cr0 | |
| and edx, ~CR0_PG_MASK | |
| mov eax, [esp] | |
| and eax, CR0_PG_MASK | |
| or edx, eax | |
| mov cr0, edx | |
| SkipCr0Label1: | |
| ; Restore CR3/CR4 | |
| mov eax, [esp+4] | |
| mov cr3, eax | |
| mov edx, cr4 | |
| and edx, ~CR4_PG_MASK | |
| mov eax, [esp+8] | |
| and eax, CR4_PG_MASK | |
| or edx, eax | |
| mov cr4, edx | |
| ; | |
| ; if new cr0 is to enable page table, change CR0 after CR3/CR4 | |
| ; | |
| mov eax, [esp] | |
| bt eax, 31 | |
| jnc SkipCr0Label2 | |
| ; Restore CR0 | |
| mov edx, cr0 | |
| and edx, ~CR0_PG_MASK | |
| mov eax, [esp] | |
| and eax, CR0_PG_MASK | |
| or edx, eax | |
| mov cr0, edx | |
| SkipCr0Label2: | |
| ; | |
| ; If NXE bit is changed to 0, change NXE after than CR regiser | |
| ; | |
| mov eax, [esp+12] | |
| bt eax, 11 | |
| jc SkipEferLabel2 | |
| ; Restore EFER MSR | |
| mov ecx, 0xC0000080 | |
| rdmsr | |
| and eax, ~EFER_PG_MASK | |
| mov ebx, [esp+12] | |
| and ebx, EFER_PG_MASK | |
| or eax, ebx | |
| wrmsr | |
| SkipEferLabel2: | |
| SkipPagetableRestore: | |
| ; pop page table related registers. | |
| add esp, 16 | |
| popad | |
| popfd | |
| add esp, 4 | |
| ret | |