1 ;------------------------------------------------------------------------------ ; 2 ; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR> 3 ; This program and the accompanying materials 4 ; are licensed and made available under the terms and conditions of the BSD License 5 ; which accompanies this distribution. The full text of the license may be found at 6 ; http://opensource.org/licenses/bsd-license.php. 7 ; 8 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 9 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 10 ; 11 ; Module Name: 12 ; 13 ; SmiEntry.asm 14 ; 15 ; Abstract: 16 ; 17 ; Code template of the SMI handler for a particular processor 18 ; 19 ;------------------------------------------------------------------------------- 20 21 ; 22 ; Variables referenced by C code 23 ; 24 EXTERNDEF SmiRendezvous:PROC 25 EXTERNDEF CpuSmmDebugEntry:PROC 26 EXTERNDEF CpuSmmDebugExit:PROC 27 EXTERNDEF gcStmSmiHandlerTemplate:BYTE 28 EXTERNDEF gcStmSmiHandlerSize:WORD 29 EXTERNDEF gcStmSmiHandlerOffset:WORD 30 EXTERNDEF gStmSmiCr3:DWORD 31 EXTERNDEF gStmSmiStack:DWORD 32 EXTERNDEF gStmSmbase:DWORD 33 EXTERNDEF gStmXdSupported:BYTE 34 EXTERNDEF gStmSmiHandlerIdtr:FWORD 35 36 MSR_IA32_MISC_ENABLE EQU 1A0h 37 MSR_EFER EQU 0c0000080h 38 MSR_EFER_XD EQU 0800h 39 40 ; 41 ; Constants relating to TXT_PROCESSOR_SMM_DESCRIPTOR 42 ; 43 DSC_OFFSET EQU 0fb00h 44 DSC_GDTPTR EQU 48h 45 DSC_GDTSIZ EQU 50h 46 DSC_CS EQU 14h 47 DSC_DS EQU 16h 48 DSC_SS EQU 18h 49 DSC_OTHERSEG EQU 1ah 50 ; 51 ; Constants relating to CPU State Save Area 52 ; 53 SSM_DR6 EQU 0ffd0h 54 SSM_DR7 EQU 0ffc8h 55 56 PROTECT_MODE_CS EQU 08h 57 PROTECT_MODE_DS EQU 20h 58 LONG_MODE_CS EQU 38h 59 TSS_SEGMENT EQU 40h 60 GDT_SIZE EQU 50h 61 62 .code 63 64 gcStmSmiHandlerTemplate LABEL BYTE 65 66 _StmSmiEntryPoint: 67 ; 68 ; The encoding of BX in 16-bit addressing mode is the same as of RDI in 64- 69 ; bit addressing mode. And that coincidence has been used in the following 70 ; "64-bit like" 16-bit code. Be aware that once RDI is referenced as a 71 ; base address register, it is actually BX that is referenced. 72 ; 73 DB 0bbh ; mov bx, imm16 74 DW offset _StmGdtDesc - _StmSmiEntryPoint + 8000h ; bx = GdtDesc offset 75 ; fix GDT descriptor 76 DB 2eh, 0a1h ; mov ax, cs:[offset16] 77 DW DSC_OFFSET + DSC_GDTSIZ 78 DB 48h ; dec ax 79 DB 2eh 80 mov [rdi], eax ; mov cs:[bx], ax 81 DB 66h, 2eh, 0a1h ; mov eax, cs:[offset16] 82 DW DSC_OFFSET + DSC_GDTPTR 83 DB 2eh 84 mov [rdi + 2], ax ; mov cs:[bx + 2], eax 85 DB 66h, 2eh 86 lgdt fword ptr [rdi] ; lgdt fword ptr cs:[bx] 87 ; Patch ProtectedMode Segment 88 DB 0b8h ; mov ax, imm16 89 DW PROTECT_MODE_CS ; set AX for segment directly 90 DB 2eh 91 mov [rdi - 2], eax ; mov cs:[bx - 2], ax 92 ; Patch ProtectedMode entry 93 DB 66h, 0bfh ; mov edi, SMBASE 94 gStmSmbase DD ? 95 lea ax, [edi + (@ProtectedMode - _StmSmiEntryPoint) + 8000h] 96 DB 2eh 97 mov [rdi - 6], ax ; mov cs:[bx - 6], eax 98 ; Switch into @ProtectedMode 99 mov rbx, cr0 100 DB 66h 101 and ebx, 9ffafff3h 102 DB 66h 103 or ebx, 00000023h 104 105 mov cr0, rbx 106 DB 66h, 0eah 107 DD ? 108 DW ? 109 110 _StmGdtDesc FWORD ? 111 @ProtectedMode: 112 mov ax, PROTECT_MODE_DS 113 mov ds, ax 114 mov es, ax 115 mov fs, ax 116 mov gs, ax 117 mov ss, ax 118 DB 0bch ; mov esp, imm32 119 gStmSmiStack DD ? 120 jmp ProtFlatMode 121 122 ProtFlatMode: 123 DB 0b8h ; mov eax, offset gStmSmiCr3 124 gStmSmiCr3 DD ? 125 mov cr3, rax 126 mov eax, 668h ; as cr4.PGE is not set here, refresh cr3 127 mov cr4, rax ; in PreModifyMtrrs() to flush TLB. 128 ; Load TSS 129 sub esp, 8 ; reserve room in stack 130 sgdt fword ptr [rsp] 131 mov eax, [rsp + 2] ; eax = GDT base 132 add esp, 8 133 mov dl, 89h 134 mov [rax + TSS_SEGMENT + 5], dl ; clear busy flag 135 mov eax, TSS_SEGMENT 136 ltr ax 137 138 ; enable NXE if supported 139 DB 0b0h ; mov al, imm8 140 gStmXdSupported DB 1 141 cmp al, 0 142 jz @SkipXd 143 ; 144 ; Check XD disable bit 145 ; 146 mov ecx, MSR_IA32_MISC_ENABLE 147 rdmsr 148 sub esp, 4 149 push rdx ; save MSR_IA32_MISC_ENABLE[63-32] 150 test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34] 151 jz @f 152 and dx, 0FFFBh ; clear XD Disable bit if it is set 153 wrmsr 154 @@: 155 mov ecx, MSR_EFER 156 rdmsr 157 or ax, MSR_EFER_XD ; enable NXE 158 wrmsr 159 jmp @XdDone 160 @SkipXd: 161 sub esp, 8 162 @XdDone: 163 164 ; Switch into @LongMode 165 push LONG_MODE_CS ; push cs hardcore here 166 call Base ; push return address for retf later 167 Base: 168 add dword ptr [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg 169 170 mov ecx, MSR_EFER 171 rdmsr 172 or ah, 1 ; enable LME 173 wrmsr 174 mov rbx, cr0 175 or ebx, 080010023h ; enable paging + WP + NE + MP + PE 176 mov cr0, rbx 177 retf 178 @LongMode: ; long mode (64-bit code) starts here 179 mov rax, offset gStmSmiHandlerIdtr 180 lidt fword ptr [rax] 181 lea ebx, [rdi + DSC_OFFSET] 182 mov ax, [rbx + DSC_DS] 183 mov ds, eax 184 mov ax, [rbx + DSC_OTHERSEG] 185 mov es, eax 186 mov fs, eax 187 mov gs, eax 188 mov ax, [rbx + DSC_SS] 189 mov ss, eax 190 191 CommonHandler: 192 mov rbx, [rsp + 0x08] ; rbx <- CpuIndex 193 194 ; 195 ; Save FP registers 196 ; 197 sub rsp, 200h 198 DB 48h ; FXSAVE64 199 fxsave [rsp] 200 201 add rsp, -20h 202 203 mov rcx, rbx 204 mov rax, CpuSmmDebugEntry 205 call rax 206 207 mov rcx, rbx 208 mov rax, SmiRendezvous ; rax <- absolute addr of SmiRedezvous 209 call rax 210 211 mov rcx, rbx 212 mov rax, CpuSmmDebugExit 213 call rax 214 215 add rsp, 20h 216 217 ; 218 ; Restore FP registers 219 ; 220 DB 48h ; FXRSTOR64 221 fxrstor [rsp] 222 223 add rsp, 200h 224 225 mov rax, offset ASM_PFX(gStmXdSupported) 226 mov al, [rax] 227 cmp al, 0 228 jz @f 229 pop rdx ; get saved MSR_IA32_MISC_ENABLE[63-32] 230 test edx, BIT2 231 jz @f 232 mov ecx, MSR_IA32_MISC_ENABLE 233 rdmsr 234 or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM 235 wrmsr 236 237 @@: 238 rsm 239 240 _StmSmiHandler: 241 ; 242 ; Check XD disable bit 243 ; 244 xor r8, r8 245 mov rax, offset ASM_PFX(gStmXdSupported) 246 mov al, [rax] 247 cmp al, 0 248 jz @StmXdDone 249 mov ecx, MSR_IA32_MISC_ENABLE 250 rdmsr 251 mov r8, rdx ; save MSR_IA32_MISC_ENABLE[63-32] 252 test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34] 253 jz @f 254 and dx, 0FFFBh ; clear XD Disable bit if it is set 255 wrmsr 256 @@: 257 mov ecx, MSR_EFER 258 rdmsr 259 or ax, MSR_EFER_XD ; enable NXE 260 wrmsr 261 @StmXdDone: 262 push r8 263 264 ; below step is needed, because STM does not run above code. 265 ; we have to run below code to set IDT/CR0/CR4 266 mov rax, offset gStmSmiHandlerIdtr 267 lidt fword ptr [rax] 268 269 mov rax, cr0 270 or eax, 80010023h ; enable paging + WP + NE + MP + PE 271 mov cr0, rax 272 mov rax, cr4 273 mov eax, 668h ; as cr4.PGE is not set here, refresh cr3 274 mov cr4, rax ; in PreModifyMtrrs() to flush TLB. 275 ; STM init finish 276 jmp CommonHandler 277 278 gcStmSmiHandlerSize DW $ - _StmSmiEntryPoint 279 gcStmSmiHandlerOffset DW _StmSmiHandler - _StmSmiEntryPoint 280 281 END 282