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