]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
UefiCpuPkg/DxeMpLib: Make sure APs in safe loop code
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / X64 / MpFuncs.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2015 - 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 ; MpFuncs.nasm
14 ;
15 ; Abstract:
16 ;
17 ; This is the assembly code for MP support
18 ;
19 ;-------------------------------------------------------------------------------
20
21 %include "MpEqu.inc"
22 extern ASM_PFX(InitializeFloatingPointUnits)
23
24 DEFAULT REL
25
26 SECTION .text
27
28 ;-------------------------------------------------------------------------------------
29 ;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
30 ;procedure serializes all the AP processors through an Init sequence. It must be
31 ;noted that APs arrive here very raw...ie: real mode, no stack.
32 ;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
33 ;IS IN MACHINE CODE.
34 ;-------------------------------------------------------------------------------------
35 global ASM_PFX(RendezvousFunnelProc)
36 ASM_PFX(RendezvousFunnelProc):
37 RendezvousFunnelProcStart:
38 ; At this point CS = 0x(vv00) and ip= 0x0.
39 ; Save BIST information to ebp firstly
40
41 BITS 16
42 mov ebp, eax ; Save BIST information
43
44 mov ax, cs
45 mov ds, ax
46 mov es, ax
47 mov ss, ax
48 xor ax, ax
49 mov fs, ax
50 mov gs, ax
51
52 mov si, BufferStartLocation
53 mov ebx, [si]
54
55 mov di, ModeOffsetLocation
56 mov eax, [di]
57 mov di, CodeSegmentLocation
58 mov edx, [di]
59 mov di, ax
60 sub di, 02h
61 mov [di],dx ; Patch long mode CS
62 sub di, 04h
63 add eax, ebx
64 mov [di],eax ; Patch address
65
66 mov si, GdtrLocation
67 o32 lgdt [cs:si]
68
69 mov si, IdtrLocation
70 o32 lidt [cs:si]
71
72 mov si, EnableExecuteDisableLocation
73 cmp byte [si], 0
74 jz SkipEnableExecuteDisableBit
75
76 ;
77 ; Enable execute disable bit
78 ;
79 mov ecx, 0c0000080h ; EFER MSR number
80 rdmsr ; Read EFER
81 bts eax, 11 ; Enable Execute Disable Bit
82 wrmsr ; Write EFER
83
84 SkipEnableExecuteDisableBit:
85
86 mov di, DataSegmentLocation
87 mov edi, [di] ; Save long mode DS in edi
88
89 mov si, Cr3Location ; Save CR3 in ecx
90 mov ecx, [si]
91
92 xor ax, ax
93 mov ds, ax ; Clear data segment
94
95 mov eax, cr0 ; Get control register 0
96 or eax, 000000003h ; Set PE bit (bit #0) & MP
97 mov cr0, eax
98
99 mov eax, cr4
100 bts eax, 5
101 mov cr4, eax
102
103 mov cr3, ecx ; Load CR3
104
105 mov ecx, 0c0000080h ; EFER MSR number
106 rdmsr ; Read EFER
107 bts eax, 8 ; Set LME=1
108 wrmsr ; Write EFER
109
110 mov eax, cr0 ; Read CR0
111 bts eax, 31 ; Set PG=1
112 mov cr0, eax ; Write CR0
113
114 jmp 0:strict dword 0 ; far jump to long mode
115 BITS 64
116 LongModeStart:
117 mov eax, edi
118 mov ds, ax
119 mov es, ax
120 mov ss, ax
121
122 mov esi, ebx
123 lea edi, [esi + InitFlagLocation]
124 cmp qword [edi], 1 ; ApInitConfig
125 jnz GetApicId
126
127 ; AP init
128 mov edi, esi
129 add edi, LockLocation
130 mov rax, NotVacantFlag
131
132 TestLock:
133 xchg qword [edi], rax
134 cmp rax, NotVacantFlag
135 jz TestLock
136
137 lea ecx, [esi + NumApsExecutingLocation]
138 inc dword [ecx]
139 mov ebx, [ecx]
140
141 Releaselock:
142 mov rax, VacantFlag
143 xchg qword [edi], rax
144 ; program stack
145 mov edi, esi
146 add edi, StackSizeLocation
147 mov eax, dword [edi]
148 mov ecx, ebx
149 inc ecx
150 mul ecx ; EAX = StackSize * (CpuNumber + 1)
151 mov edi, esi
152 add edi, StackStartAddressLocation
153 add rax, qword [edi]
154 mov rsp, rax
155 jmp CProcedureInvoke
156
157 GetApicId:
158 mov eax, 0
159 cpuid
160 cmp eax, 0bh
161 jb NoX2Apic ; CPUID level below CPUID_EXTENDED_TOPOLOGY
162
163 mov eax, 0bh
164 xor ecx, ecx
165 cpuid
166 test ebx, 0ffffh
167 jz NoX2Apic ; CPUID.0BH:EBX[15:0] is zero
168
169 ; Processor is x2APIC capable; 32-bit x2APIC ID is already in EDX
170 jmp GetProcessorNumber
171
172 NoX2Apic:
173 ; Processor is not x2APIC capable, so get 8-bit APIC ID
174 mov eax, 1
175 cpuid
176 shr ebx, 24
177 mov edx, ebx
178
179 GetProcessorNumber:
180 ;
181 ; Get processor number for this AP
182 ; Note that BSP may become an AP due to SwitchBsp()
183 ;
184 xor ebx, ebx
185 lea eax, [esi + CpuInfoLocation]
186 mov edi, [eax]
187
188 GetNextProcNumber:
189 cmp dword [edi], edx ; APIC ID match?
190 jz ProgramStack
191 add edi, 20
192 inc ebx
193 jmp GetNextProcNumber
194
195 ProgramStack:
196 mov rsp, qword [edi + 12]
197
198 CProcedureInvoke:
199 push rbp ; Push BIST data at top of AP stack
200 xor rbp, rbp ; Clear ebp for call stack trace
201 push rbp
202 mov rbp, rsp
203
204 mov rax, ASM_PFX(InitializeFloatingPointUnits)
205 sub rsp, 20h
206 call rax ; Call assembly function to initialize FPU per UEFI spec
207 add rsp, 20h
208
209 mov edx, ebx ; edx is NumApsExecuting
210 mov ecx, esi
211 add ecx, LockLocation ; rcx is address of exchange info data buffer
212
213 mov edi, esi
214 add edi, ApProcedureLocation
215 mov rax, qword [edi]
216
217 sub rsp, 20h
218 call rax ; Invoke C function
219 add rsp, 20h
220 jmp $ ; Should never reach here
221
222 RendezvousFunnelProcEnd:
223
224 ;-------------------------------------------------------------------------------------
225 ; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);
226 ;-------------------------------------------------------------------------------------
227 global ASM_PFX(AsmRelocateApLoop)
228 ASM_PFX(AsmRelocateApLoop):
229 AsmRelocateApLoopStart:
230 mov rax, [rsp + 40] ; CountTofinish
231 lock dec dword [rax] ; (*CountTofinish)--
232 mov rsp, r9
233 push rcx
234 push rdx
235
236 lea rsi, [PmEntry] ; rsi <- The start address of transition code
237
238 push r8
239 push rsi
240 DB 0x48
241 retf
242 BITS 32
243 PmEntry:
244 mov eax, cr0
245 btr eax, 31 ; Clear CR0.PG
246 mov cr0, eax ; Disable paging and caches
247
248 mov ebx, edx ; Save EntryPoint to rbx, for rdmsr will overwrite rdx
249 mov ecx, 0xc0000080
250 rdmsr
251 and ah, ~ 1 ; Clear LME
252 wrmsr
253 mov eax, cr4
254 and al, ~ (1 << 5) ; Clear PAE
255 mov cr4, eax
256
257 pop edx
258 add esp, 4
259 pop ecx,
260 add esp, 4
261 cmp cl, 1 ; Check mwait-monitor support
262 jnz HltLoop
263 mov ebx, edx ; Save C-State to ebx
264 MwaitLoop:
265 mov eax, esp ; Set Monitor Address
266 xor ecx, ecx ; ecx = 0
267 xor edx, edx ; edx = 0
268 monitor
269 shl ebx, 4
270 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]
271 mwait
272 jmp MwaitLoop
273 HltLoop:
274 cli
275 hlt
276 jmp HltLoop
277 ret
278 BITS 64
279 AsmRelocateApLoopEnd:
280
281 ;-------------------------------------------------------------------------------------
282 ; AsmGetAddressMap (&AddressMap);
283 ;-------------------------------------------------------------------------------------
284 global ASM_PFX(AsmGetAddressMap)
285 ASM_PFX(AsmGetAddressMap):
286 mov rax, ASM_PFX(RendezvousFunnelProc)
287 mov qword [rcx], rax
288 mov qword [rcx + 8h], LongModeStart - RendezvousFunnelProcStart
289 mov qword [rcx + 10h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
290 mov rax, ASM_PFX(AsmRelocateApLoop)
291 mov qword [rcx + 18h], rax
292 mov qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
293 ret
294
295 ;-------------------------------------------------------------------------------------
296 ;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
297 ;about to become an AP. It switches its stack with the current AP.
298 ;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
299 ;-------------------------------------------------------------------------------------
300 global ASM_PFX(AsmExchangeRole)
301 ASM_PFX(AsmExchangeRole):
302 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
303 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
304
305 push rax
306 push rbx
307 push rcx
308 push rdx
309 push rsi
310 push rdi
311 push rbp
312 push r8
313 push r9
314 push r10
315 push r11
316 push r12
317 push r13
318 push r14
319 push r15
320
321 mov rax, cr0
322 push rax
323
324 mov rax, cr4
325 push rax
326
327 ; rsi contains MyInfo pointer
328 mov rsi, rcx
329
330 ; rdi contains OthersInfo pointer
331 mov rdi, rdx
332
333 ;Store EFLAGS, GDTR and IDTR regiter to stack
334 pushfq
335 sgdt [rsi + 16]
336 sidt [rsi + 26]
337
338 ; Store the its StackPointer
339 mov [rsi + 8], rsp
340
341 ; update its switch state to STORED
342 mov byte [rsi], CPU_SWITCH_STATE_STORED
343
344 WaitForOtherStored:
345 ; wait until the other CPU finish storing its state
346 cmp byte [rdi], CPU_SWITCH_STATE_STORED
347 jz OtherStored
348 pause
349 jmp WaitForOtherStored
350
351 OtherStored:
352 ; Since another CPU already stored its state, load them
353 ; load GDTR value
354 lgdt [rdi + 16]
355
356 ; load IDTR value
357 lidt [rdi + 26]
358
359 ; load its future StackPointer
360 mov rsp, [rdi + 8]
361
362 ; update the other CPU's switch state to LOADED
363 mov byte [rdi], CPU_SWITCH_STATE_LOADED
364
365 WaitForOtherLoaded:
366 ; wait until the other CPU finish loading new state,
367 ; otherwise the data in stack may corrupt
368 cmp byte [rsi], CPU_SWITCH_STATE_LOADED
369 jz OtherLoaded
370 pause
371 jmp WaitForOtherLoaded
372
373 OtherLoaded:
374 ; since the other CPU already get the data it want, leave this procedure
375 popfq
376
377 pop rax
378 mov cr4, rax
379
380 pop rax
381 mov cr0, rax
382
383 pop r15
384 pop r14
385 pop r13
386 pop r12
387 pop r11
388 pop r10
389 pop r9
390 pop r8
391 pop rbp
392 pop rdi
393 pop rsi
394 pop rdx
395 pop rcx
396 pop rbx
397 pop rax
398
399 ret