]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
bfc3ff1f5c7af7122a6a2546ff795169936720c1
[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 esi, ebx
129 mov edi, esi
130 add edi, LockLocation
131 mov rax, NotVacantFlag
132
133 TestLock:
134 xchg qword [edi], rax
135 cmp rax, NotVacantFlag
136 jz TestLock
137
138 lea ecx, [esi + InitFlagLocation]
139 inc dword [ecx]
140 mov ebx, [ecx]
141
142 Releaselock:
143 mov rax, VacantFlag
144 xchg qword [edi], rax
145 ; program stack
146 mov edi, esi
147 add edi, StackSizeLocation
148 mov eax, dword [edi]
149 mov ecx, ebx
150 inc ecx
151 mul ecx ; EAX = StackSize * (CpuNumber + 1)
152 mov edi, esi
153 add edi, StackStartAddressLocation
154 add rax, qword [edi]
155 mov rsp, rax
156 jmp CProcedureInvoke
157
158 GetApicId:
159 mov eax, 0
160 cpuid
161 cmp eax, 0bh
162 jnb X2Apic
163 ; Processor is not x2APIC capable, so get 8-bit APIC ID
164 mov eax, 1
165 cpuid
166 shr ebx, 24
167 mov edx, ebx
168 jmp GetProcessorNumber
169
170 X2Apic:
171 ; Processor is x2APIC capable, so get 32-bit x2APIC ID
172 mov eax, 0bh
173 xor ecx, ecx
174 cpuid
175 ; edx save x2APIC ID
176
177 GetProcessorNumber:
178 ;
179 ; Get processor number for this AP
180 ; Note that BSP may become an AP due to SwitchBsp()
181 ;
182 xor ebx, ebx
183 lea eax, [esi + CpuInfoLocation]
184 mov edi, [eax]
185
186 GetNextProcNumber:
187 cmp dword [edi], edx ; APIC ID match?
188 jz ProgramStack
189 add edi, 16
190 inc ebx
191 jmp GetNextProcNumber
192
193 ProgramStack:
194 xor rsp, rsp
195 mov esp, dword [edi + 12]
196
197 CProcedureInvoke:
198 push rbp ; Push BIST data at top of AP stack
199 xor rbp, rbp ; Clear ebp for call stack trace
200 push rbp
201 mov rbp, rsp
202
203 mov rax, ASM_PFX(InitializeFloatingPointUnits)
204 sub rsp, 20h
205 call rax ; Call assembly function to initialize FPU per UEFI spec
206 add rsp, 20h
207
208 mov edx, ebx ; edx is NumApsExecuting
209 mov ecx, esi
210 add ecx, LockLocation ; rcx is address of exchange info data buffer
211
212 mov edi, esi
213 add edi, ApProcedureLocation
214 mov rax, qword [edi]
215
216 sub rsp, 20h
217 call rax ; Invoke C function
218 add rsp, 20h
219 jmp $ ; Should never reach here
220
221 RendezvousFunnelProcEnd:
222
223 ;-------------------------------------------------------------------------------------
224 ; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment);
225 ;-------------------------------------------------------------------------------------
226 global ASM_PFX(AsmRelocateApLoop)
227 ASM_PFX(AsmRelocateApLoop):
228 AsmRelocateApLoopStart:
229 push rcx
230 push rdx
231
232 lea rsi, [PmEntry] ; rsi <- The start address of transition code
233
234 push r8
235 push rsi
236 DB 0x48
237 retf
238 BITS 32
239 PmEntry:
240 mov eax, cr0
241 btr eax, 31 ; Clear CR0.PG
242 mov cr0, eax ; Disable paging and caches
243
244 mov ebx, edx ; Save EntryPoint to rbx, for rdmsr will overwrite rdx
245 mov ecx, 0xc0000080
246 rdmsr
247 and ah, ~ 1 ; Clear LME
248 wrmsr
249 mov eax, cr4
250 and al, ~ (1 << 5) ; Clear PAE
251 mov cr4, eax
252
253 pop edx
254 add esp, 4
255 pop ecx,
256 add esp, 4
257 cmp cl, 1 ; Check mwait-monitor support
258 jnz HltLoop
259 mov ebx, edx ; Save C-State to ebx
260 MwaitLoop:
261 mov eax, esp ; Set Monitor Address
262 xor ecx, ecx ; ecx = 0
263 xor edx, edx ; edx = 0
264 monitor
265 shl ebx, 4
266 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]
267 mwait
268 jmp MwaitLoop
269 HltLoop:
270 cli
271 hlt
272 jmp HltLoop
273 ret
274 BITS 64
275 AsmRelocateApLoopEnd:
276
277 ;-------------------------------------------------------------------------------------
278 ; AsmGetAddressMap (&AddressMap);
279 ;-------------------------------------------------------------------------------------
280 global ASM_PFX(AsmGetAddressMap)
281 ASM_PFX(AsmGetAddressMap):
282 mov rax, ASM_PFX(RendezvousFunnelProc)
283 mov qword [rcx], rax
284 mov qword [rcx + 8h], LongModeStart - RendezvousFunnelProcStart
285 mov qword [rcx + 10h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
286 mov rax, ASM_PFX(AsmRelocateApLoop)
287 mov qword [rcx + 18h], rax
288 mov qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
289 ret
290
291 ;-------------------------------------------------------------------------------------
292 ;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
293 ;about to become an AP. It switches its stack with the current AP.
294 ;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
295 ;-------------------------------------------------------------------------------------
296 global ASM_PFX(AsmExchangeRole)
297 ASM_PFX(AsmExchangeRole):
298 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
299 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
300
301 push rax
302 push rbx
303 push rcx
304 push rdx
305 push rsi
306 push rdi
307 push rbp
308 push r8
309 push r9
310 push r10
311 push r11
312 push r12
313 push r13
314 push r14
315 push r15
316
317 mov rax, cr0
318 push rax
319
320 mov rax, cr4
321 push rax
322
323 ; rsi contains MyInfo pointer
324 mov rsi, rcx
325
326 ; rdi contains OthersInfo pointer
327 mov rdi, rdx
328
329 ;Store EFLAGS, GDTR and IDTR regiter to stack
330 pushfq
331 sgdt [rsi + 16]
332 sidt [rsi + 26]
333
334 ; Store the its StackPointer
335 mov [rsi + 8], rsp
336
337 ; update its switch state to STORED
338 mov byte [rsi], CPU_SWITCH_STATE_STORED
339
340 WaitForOtherStored:
341 ; wait until the other CPU finish storing its state
342 cmp byte [rdi], CPU_SWITCH_STATE_STORED
343 jz OtherStored
344 pause
345 jmp WaitForOtherStored
346
347 OtherStored:
348 ; Since another CPU already stored its state, load them
349 ; load GDTR value
350 lgdt [rdi + 16]
351
352 ; load IDTR value
353 lidt [rdi + 26]
354
355 ; load its future StackPointer
356 mov rsp, [rdi + 8]
357
358 ; update the other CPU's switch state to LOADED
359 mov byte [rdi], CPU_SWITCH_STATE_LOADED
360
361 WaitForOtherLoaded:
362 ; wait until the other CPU finish loading new state,
363 ; otherwise the data in stack may corrupt
364 cmp byte [rsi], CPU_SWITCH_STATE_LOADED
365 jz OtherLoaded
366 pause
367 jmp WaitForOtherLoaded
368
369 OtherLoaded:
370 ; since the other CPU already get the data it want, leave this procedure
371 popfq
372
373 pop rax
374 mov cr4, rax
375
376 pop rax
377 mov cr0, rax
378
379 pop r15
380 pop r14
381 pop r13
382 pop r12
383 pop r11
384 pop r10
385 pop r9
386 pop r8
387 pop rbp
388 pop rdi
389 pop rsi
390 pop rdx
391 pop rcx
392 pop rbx
393 pop rax
394
395 ret