]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
UefiCpuPkg: Put APs in 64 bit mode before handoff to OS.
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / X64 / MpFuncs.nasm
CommitLineData
d94e5f67 1;------------------------------------------------------------------------------ ;\r
facf52ae 2; Copyright (c) 2015 - 2023, Intel Corporation. All rights reserved.<BR>\r
0acd8697 3; SPDX-License-Identifier: BSD-2-Clause-Patent\r
d94e5f67
JF
4;\r
5; Module Name:\r
6;\r
7; MpFuncs.nasm\r
8;\r
9; Abstract:\r
10;\r
11; This is the assembly code for MP support\r
12;\r
13;-------------------------------------------------------------------------------\r
14\r
15%include "MpEqu.inc"\r
16extern ASM_PFX(InitializeFloatingPointUnits)\r
17\r
e2289d19
BS
18%macro OneTimeCall 1\r
19 jmp %1\r
20%1 %+ OneTimerCallReturn:\r
21%endmacro\r
22\r
23%macro OneTimeCallRet 1\r
24 jmp %1 %+ OneTimerCallReturn\r
25%endmacro\r
26\r
d94e5f67
JF
27DEFAULT REL\r
28\r
29SECTION .text\r
30\r
31;-------------------------------------------------------------------------------------\r
32;RendezvousFunnelProc procedure follows. All APs execute their procedure. This\r
33;procedure serializes all the AP processors through an Init sequence. It must be\r
34;noted that APs arrive here very raw...ie: real mode, no stack.\r
35;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC\r
36;IS IN MACHINE CODE.\r
37;-------------------------------------------------------------------------------------\r
d94e5f67
JF
38RendezvousFunnelProcStart:\r
39; At this point CS = 0x(vv00) and ip= 0x0.\r
40; Save BIST information to ebp firstly\r
41\r
42BITS 16\r
43 mov ebp, eax ; Save BIST information\r
44\r
45 mov ax, cs\r
46 mov ds, ax\r
47 mov es, ax\r
48 mov ss, ax\r
49 xor ax, ax\r
50 mov fs, ax\r
51 mov gs, ax\r
52\r
2fba7d4e 53 mov si, MP_CPU_EXCHANGE_INFO_FIELD (BufferStart)\r
d94e5f67
JF
54 mov ebx, [si]\r
55\r
2fba7d4e 56 mov si, MP_CPU_EXCHANGE_INFO_FIELD (DataSegment)\r
f32bfe6d
JW
57 mov edx, [si]\r
58\r
59 ;\r
60 ; Get start address of 32-bit code in low memory (<1MB)\r
61 ;\r
2fba7d4e 62 mov edi, MP_CPU_EXCHANGE_INFO_FIELD (ModeTransitionMemory)\r
d94e5f67 63\r
2fba7d4e 64 mov si, MP_CPU_EXCHANGE_INFO_FIELD (GdtrProfile)\r
d94e5f67
JF
65o32 lgdt [cs:si]\r
66\r
f32bfe6d
JW
67 ;\r
68 ; Switch to protected mode\r
69 ;\r
70 mov eax, cr0 ; Get control register 0\r
71 or eax, 000000003h ; Set PE bit (bit #0) & MP\r
72 mov cr0, eax\r
73\r
74 ; Switch to 32-bit code (>1MB)\r
75o32 jmp far [cs:di]\r
76\r
77;\r
78; Following code must be copied to memory with type of EfiBootServicesCode.\r
79; This is required if NX is enabled for EfiBootServicesCode of memory.\r
80;\r
81BITS 32\r
82Flat32Start: ; protected mode entry point\r
83 mov ds, dx\r
84 mov es, dx\r
85 mov fs, dx\r
86 mov gs, dx\r
87 mov ss, dx\r
5c66d125
JF
88\r
89 ;\r
90 ; Enable execute disable bit\r
91 ;\r
2fba7d4e 92 mov esi, MP_CPU_EXCHANGE_INFO_FIELD (EnableExecuteDisable)\r
f32bfe6d
JW
93 cmp byte [ebx + esi], 0\r
94 jz SkipEnableExecuteDisableBit\r
95\r
5c66d125
JF
96 mov ecx, 0c0000080h ; EFER MSR number\r
97 rdmsr ; Read EFER\r
98 bts eax, 11 ; Enable Execute Disable Bit\r
99 wrmsr ; Write EFER\r
100\r
101SkipEnableExecuteDisableBit:\r
f32bfe6d
JW
102 ;\r
103 ; Enable PAE\r
104 ;\r
d94e5f67
JF
105 mov eax, cr4\r
106 bts eax, 5\r
09f69a87 107\r
2fba7d4e 108 mov esi, MP_CPU_EXCHANGE_INFO_FIELD (Enable5LevelPaging)\r
09f69a87
RN
109 cmp byte [ebx + esi], 0\r
110 jz SkipEnable5LevelPaging\r
111\r
112 ;\r
113 ; Enable 5 Level Paging\r
114 ;\r
115 bts eax, 12 ; Set LA57=1.\r
116\r
117SkipEnable5LevelPaging:\r
118\r
d94e5f67
JF
119 mov cr4, eax\r
120\r
f32bfe6d
JW
121 ;\r
122 ; Load page table\r
123 ;\r
2fba7d4e 124 mov esi, MP_CPU_EXCHANGE_INFO_FIELD (Cr3) ; Save CR3 in ecx\r
f32bfe6d 125 mov ecx, [ebx + esi]\r
d94e5f67
JF
126 mov cr3, ecx ; Load CR3\r
127\r
f32bfe6d
JW
128 ;\r
129 ; Enable long mode\r
130 ;\r
d94e5f67
JF
131 mov ecx, 0c0000080h ; EFER MSR number\r
132 rdmsr ; Read EFER\r
133 bts eax, 8 ; Set LME=1\r
134 wrmsr ; Write EFER\r
135\r
f32bfe6d
JW
136 ;\r
137 ; Enable paging\r
138 ;\r
d94e5f67
JF
139 mov eax, cr0 ; Read CR0\r
140 bts eax, 31 ; Set PG=1\r
141 mov cr0, eax ; Write CR0\r
142\r
f32bfe6d
JW
143 ;\r
144 ; Far jump to 64-bit code\r
145 ;\r
2fba7d4e 146 mov edi, MP_CPU_EXCHANGE_INFO_FIELD (ModeHighMemory)\r
f32bfe6d
JW
147 add edi, ebx\r
148 jmp far [edi]\r
149\r
d94e5f67 150BITS 64\r
e2289d19 151\r
d94e5f67 152LongModeStart:\r
845c5be1 153 mov esi, ebx\r
367604b2
ZL
154\r
155 ; Set IDT table at the start of 64 bit code\r
156 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (IdtrProfile)]\r
157 lidt [edi]\r
158\r
2fba7d4e 159 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (InitFlag)]\r
845c5be1
JF
160 cmp qword [edi], 1 ; ApInitConfig\r
161 jnz GetApicId\r
162\r
0594ec41
ED
163 ; Increment the number of APs executing here as early as possible\r
164 ; This is decremented in C code when AP is finished executing\r
165 mov edi, esi\r
2fba7d4e 166 add edi, MP_CPU_EXCHANGE_INFO_FIELD (NumApsExecuting)\r
0594ec41
ED
167 lock inc dword [edi]\r
168\r
845c5be1 169 ; AP init\r
62f2cf57 170 mov edi, esi\r
2fba7d4e 171 add edi, MP_CPU_EXCHANGE_INFO_FIELD (ApIndex)\r
62f2cf57
RN
172 mov ebx, 1\r
173 lock xadd dword [edi], ebx ; EBX = ApIndex++\r
174 inc ebx ; EBX is CpuNumber\r
d94e5f67 175\r
845c5be1 176 ; program stack\r
d94e5f67 177 mov edi, esi\r
2fba7d4e 178 add edi, MP_CPU_EXCHANGE_INFO_FIELD (StackSize)\r
845c5be1
JF
179 mov eax, dword [edi]\r
180 mov ecx, ebx\r
181 inc ecx\r
182 mul ecx ; EAX = StackSize * (CpuNumber + 1)\r
d94e5f67 183 mov edi, esi\r
2fba7d4e 184 add edi, MP_CPU_EXCHANGE_INFO_FIELD (StackStart)\r
d94e5f67
JF
185 add rax, qword [edi]\r
186 mov rsp, rax\r
7b7508ad 187\r
7b7508ad 188 ;\r
e2289d19 189 ; Setup the GHCB when AMD SEV-ES active.\r
7b7508ad 190 ;\r
e2289d19 191 OneTimeCall SevEsSetupGhcb\r
845c5be1
JF
192 jmp CProcedureInvoke\r
193\r
194GetApicId:\r
7b7508ad 195 ;\r
e2289d19 196 ; Use the GHCB protocol to get the ApicId when SEV-ES is active.\r
7b7508ad 197 ;\r
e2289d19 198 OneTimeCall SevEsGetApicId\r
7b7508ad
TL
199\r
200DoCpuid:\r
845c5be1
JF
201 mov eax, 0\r
202 cpuid\r
203 cmp eax, 0bh\r
1cbd8330
LE
204 jb NoX2Apic ; CPUID level below CPUID_EXTENDED_TOPOLOGY\r
205\r
206 mov eax, 0bh\r
207 xor ecx, ecx\r
208 cpuid\r
209 test ebx, 0ffffh\r
210 jz NoX2Apic ; CPUID.0BH:EBX[15:0] is zero\r
211\r
212 ; Processor is x2APIC capable; 32-bit x2APIC ID is already in EDX\r
213 jmp GetProcessorNumber\r
214\r
215NoX2Apic:\r
845c5be1
JF
216 ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
217 mov eax, 1\r
218 cpuid\r
219 shr ebx, 24\r
220 mov edx, ebx\r
845c5be1 221\r
845c5be1
JF
222GetProcessorNumber:\r
223 ;\r
224 ; Get processor number for this AP\r
225 ; Note that BSP may become an AP due to SwitchBsp()\r
226 ;\r
227 xor ebx, ebx\r
2fba7d4e 228 lea eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (CpuInfo)]\r
edd74ad3 229 mov rdi, [eax]\r
d94e5f67 230\r
845c5be1 231GetNextProcNumber:\r
2fba7d4e 232 cmp dword [rdi + CPU_INFO_IN_HOB.InitialApicId], edx ; APIC ID match?\r
845c5be1 233 jz ProgramStack\r
2fba7d4e 234 add rdi, CPU_INFO_IN_HOB_size\r
845c5be1 235 inc ebx\r
7367cc6c 236 jmp GetNextProcNumber\r
845c5be1
JF
237\r
238ProgramStack:\r
2fba7d4e 239 mov rsp, qword [rdi + CPU_INFO_IN_HOB.ApTopOfStack]\r
d94e5f67
JF
240\r
241CProcedureInvoke:\r
9ab2b34d
YX
242 ;\r
243 ; Reserve 8 bytes for CpuMpData.\r
244 ; When the AP wakes up again via INIT-SIPI-SIPI, push 0 will cause the existing CpuMpData to be overwritten with 0.\r
245 ; CpuMpData is filled in via InitializeApData() during the first time INIT-SIPI-SIPI,\r
246 ; while overwirrten may occurs when under ApInHltLoop but InitFlag is not set to ApInitConfig.\r
247 ; Therefore reservation is implemented by sub rsp instead of push 0.\r
248 ;\r
249 sub rsp, 8\r
8396e2dd
JF
250 push rbp ; Push BIST data at top of AP stack\r
251 xor rbp, rbp ; Clear ebp for call stack trace\r
d94e5f67
JF
252 push rbp\r
253 mov rbp, rsp\r
254\r
9ab2b34d 255 push qword 0 ; Push 8 bytes for alignment\r
2fba7d4e 256 mov rax, qword [esi + MP_CPU_EXCHANGE_INFO_FIELD (InitializeFloatingPointUnits)]\r
d94e5f67
JF
257 sub rsp, 20h\r
258 call rax ; Call assembly function to initialize FPU per UEFI spec\r
259 add rsp, 20h\r
260\r
37676b9f 261 mov edx, ebx ; edx is ApIndex\r
d94e5f67 262 mov ecx, esi\r
2fba7d4e 263 add ecx, MP_CPU_EXCHANGE_INFO_OFFSET ; rcx is address of exchange info data buffer\r
d94e5f67
JF
264\r
265 mov edi, esi\r
2fba7d4e 266 add edi, MP_CPU_EXCHANGE_INFO_FIELD (CFunction)\r
d94e5f67
JF
267 mov rax, qword [edi]\r
268\r
269 sub rsp, 20h\r
8396e2dd 270 call rax ; Invoke C function\r
d94e5f67 271 add rsp, 20h\r
8396e2dd 272 jmp $ ; Should never reach here\r
d94e5f67 273\r
b4d7b9d2
RN
274;\r
275; Required for the AMD SEV helper functions\r
276;\r
277%include "AmdSev.nasm"\r
7b7508ad 278\r
b4d7b9d2 279RendezvousFunnelProcEnd:\r
7b7508ad 280\r
76157021 281;-------------------------------------------------------------------------------------\r
cbcf0cd6 282; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);\r
76157021 283;-------------------------------------------------------------------------------------\r
73ccde8f 284AsmRelocateApLoopStart:\r
cbcf0cd6
YX
285BITS 64\r
286 cmp qword [rsp + 56], 0 ; SevEsAPJumpTable\r
287 je NoSevEs\r
288\r
289 ;\r
290 ; Perform some SEV-ES related setup before leaving 64-bit mode\r
291 ;\r
292 push rcx\r
293 push rdx\r
294\r
295 ;\r
296 ; Get the RDX reset value using CPUID\r
297 ;\r
298 mov rax, 1\r
299 cpuid\r
300 mov rsi, rax ; Save off the reset value for RDX\r
301\r
302 ;\r
303 ; Prepare the GHCB for the AP_HLT_LOOP VMGEXIT call\r
304 ; - Must be done while in 64-bit long mode so that writes to\r
305 ; the GHCB memory will be unencrypted.\r
306 ; - No NAE events can be generated once this is set otherwise\r
307 ; the AP_RESET_HOLD SW_EXITCODE will be overwritten.\r
308 ;\r
309 mov rcx, 0xc0010130\r
310 rdmsr ; Retrieve current GHCB address\r
311 shl rdx, 32\r
312 or rdx, rax\r
313\r
314 mov rdi, rdx\r
315 xor rax, rax\r
316 mov rcx, 0x800\r
317 shr rcx, 3\r
318 rep stosq ; Clear the GHCB\r
319\r
320 mov rax, 0x80000004 ; VMGEXIT AP_RESET_HOLD\r
321 mov [rdx + 0x390], rax\r
322 mov rax, 114 ; Set SwExitCode valid bit\r
323 bts [rdx + 0x3f0], rax\r
324 inc rax ; Set SwExitInfo1 valid bit\r
325 bts [rdx + 0x3f0], rax\r
326 inc rax ; Set SwExitInfo2 valid bit\r
327 bts [rdx + 0x3f0], rax\r
328\r
329 pop rdx\r
330 pop rcx\r
331\r
332NoSevEs:\r
333 cli ; Disable interrupt before switching to 32-bit mode\r
334 mov rax, [rsp + 40] ; CountTofinish\r
9f91cb01 335 lock dec dword [rax] ; (*CountTofinish)--\r
76157021 336\r
cbcf0cd6
YX
337 mov r10, [rsp + 48] ; Pm16CodeSegment\r
338 mov rax, [rsp + 56] ; SevEsAPJumpTable\r
339 mov rbx, [rsp + 64] ; WakeupBuffer\r
340 mov rsp, r9 ; TopOfApStack\r
341\r
342 push rax ; Save SevEsAPJumpTable\r
343 push rbx ; Save WakeupBuffer\r
344 push r10 ; Save Pm16CodeSegment\r
345 push rcx ; Save MwaitSupport\r
346 push rdx ; Save ApTargetCState\r
347\r
348 lea rax, [PmEntry] ; rax <- The start address of transition code\r
349\r
350 push r8\r
351 push rax\r
352\r
353 ;\r
354 ; Clear R8 - R15, for reset, before going into 32-bit mode\r
355 ;\r
356 xor r8, r8\r
357 xor r9, r9\r
358 xor r10, r10\r
359 xor r11, r11\r
360 xor r12, r12\r
361 xor r13, r13\r
362 xor r14, r14\r
363 xor r15, r15\r
364\r
365 ;\r
366 ; Far return into 32-bit mode\r
367 ;\r
368 retfq\r
369\r
370BITS 32\r
371PmEntry:\r
372 mov eax, cr0\r
373 btr eax, 31 ; Clear CR0.PG\r
374 mov cr0, eax ; Disable paging and caches\r
375\r
376 mov ecx, 0xc0000080\r
377 rdmsr\r
378 and ah, ~ 1 ; Clear LME\r
379 wrmsr\r
380 mov eax, cr4\r
381 and al, ~ (1 << 5) ; Clear PAE\r
382 mov cr4, eax\r
383\r
384 pop edx\r
385 add esp, 4\r
386 pop ecx,\r
387 add esp, 4\r
20da7ca4
TL
388\r
389MwaitCheck:\r
76157021
JF
390 cmp cl, 1 ; Check mwait-monitor support\r
391 jnz HltLoop\r
cbcf0cd6 392 mov ebx, edx ; Save C-State to ebx\r
76157021 393MwaitLoop:\r
a7bbe9d2 394 cli\r
cbcf0cd6 395 mov eax, esp ; Set Monitor Address\r
76157021
JF
396 xor ecx, ecx ; ecx = 0\r
397 xor edx, edx ; edx = 0\r
398 monitor\r
76157021 399 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]\r
f56379f3 400 shl eax, 4\r
76157021
JF
401 mwait\r
402 jmp MwaitLoop\r
20da7ca4 403\r
76157021 404HltLoop:\r
cbcf0cd6
YX
405 pop edx ; PM16CodeSegment\r
406 add esp, 4\r
407 pop ebx ; WakeupBuffer\r
408 add esp, 4\r
409 pop eax ; SevEsAPJumpTable\r
410 add esp, 4\r
411 cmp eax, 0 ; Check for SEV-ES\r
412 je DoHlt\r
413\r
414 cli\r
415 ;\r
416 ; SEV-ES is enabled, use VMGEXIT (GHCB information already\r
417 ; set by caller)\r
418 ;\r
419BITS 64\r
420 rep vmmcall\r
421BITS 32\r
422\r
423 ;\r
424 ; Back from VMGEXIT AP_HLT_LOOP\r
425 ; Push the FLAGS/CS/IP values to use\r
426 ;\r
427 push word 0x0002 ; EFLAGS\r
428 xor ecx, ecx\r
429 mov cx, [eax + 2] ; CS\r
430 push cx\r
431 mov cx, [eax] ; IP\r
432 push cx\r
433 push word 0x0000 ; For alignment, will be discarded\r
434\r
435 push edx\r
436 push ebx\r
437\r
438 mov edx, esi ; Restore RDX reset value\r
439\r
440 retf\r
441\r
442DoHlt:\r
76157021
JF
443 cli\r
444 hlt\r
cbcf0cd6 445 jmp DoHlt\r
20da7ca4 446\r
cbcf0cd6 447BITS 64\r
76157021
JF
448AsmRelocateApLoopEnd:\r
449\r
facf52ae
XY
450;-------------------------------------------------------------------------------------\r
451; AsmRelocateApLoop (MwaitSupport, ApTargetCState, TopOfApStack, CountTofinish, Cr3);\r
452; This function is called during the finalizaiton of Mp initialization before booting\r
453; to OS, and aim to put Aps either in Mwait or HLT.\r
454;-------------------------------------------------------------------------------------\r
455; +----------------+\r
456; | Cr3 | rsp+40\r
457; +----------------+\r
458; | CountTofinish | r9\r
459; +----------------+\r
460; | TopOfApStack | r8\r
461; +----------------+\r
462; | ApTargetCState | rdx\r
463; +----------------+\r
464; | MwaitSupport | rcx\r
465; +----------------+\r
466; | the return |\r
467; +----------------+ low address\r
468\r
469AsmRelocateApLoopGenericStart:\r
470 mov rax, r9 ; CountTofinish\r
471 lock dec dword [rax] ; (*CountTofinish)--\r
472\r
473 mov rax, [rsp + 40] ; Cr3\r
474 ; Do not push on old stack, since old stack is not mapped\r
475 ; in the page table pointed by cr3\r
476 mov cr3, rax\r
477 mov rsp, r8 ; TopOfApStack\r
478\r
479MwaitCheckGeneric:\r
480 cmp cl, 1 ; Check mwait-monitor support\r
481 jnz HltLoopGeneric\r
482 mov rbx, rdx ; Save C-State to ebx\r
483\r
484MwaitLoopGeneric:\r
485 cli\r
486 mov rax, rsp ; Set Monitor Address\r
487 xor ecx, ecx ; ecx = 0\r
488 xor edx, edx ; edx = 0\r
489 monitor\r
490 mov rax, rbx ; Mwait Cx, Target C-State per eax[7:4]\r
491 shl eax, 4\r
492 mwait\r
493 jmp MwaitLoopGeneric\r
494\r
495HltLoopGeneric:\r
496 cli\r
497 hlt\r
498 jmp HltLoopGeneric\r
499\r
500AsmRelocateApLoopGenericEnd:\r
501\r
d94e5f67
JF
502;-------------------------------------------------------------------------------------\r
503; AsmGetAddressMap (&AddressMap);\r
504;-------------------------------------------------------------------------------------\r
505global ASM_PFX(AsmGetAddressMap)\r
506ASM_PFX(AsmGetAddressMap):\r
76323c31 507 lea rax, [RendezvousFunnelProcStart]\r
2fba7d4e
RN
508 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelAddress], rax\r
509 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.ModeEntryOffset], LongModeStart - RendezvousFunnelProcStart\r
510 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelSize], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
facf52ae
XY
511lea rax, [AsmRelocateApLoopGenericStart]\r
512 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddressGeneric], rax\r
513 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSizeGeneric], AsmRelocateApLoopGenericEnd - AsmRelocateApLoopGenericStart\r
76323c31 514 lea rax, [AsmRelocateApLoopStart]\r
2fba7d4e
RN
515 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddress], rax\r
516 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSize], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
517 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.ModeTransitionOffset], Flat32Start - RendezvousFunnelProcStart\r
2fba7d4e
RN
518 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealNoNxOffset], SwitchToRealProcStart - Flat32Start\r
519 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeOffset], PM16Mode - RendezvousFunnelProcStart\r
520 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeSize], SwitchToRealProcEnd - PM16Mode\r
d94e5f67
JF
521 ret\r
522\r
523;-------------------------------------------------------------------------------------\r
524;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is\r
8396e2dd 525;about to become an AP. It switches its stack with the current AP.\r
d94e5f67
JF
526;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);\r
527;-------------------------------------------------------------------------------------\r
528global ASM_PFX(AsmExchangeRole)\r
529ASM_PFX(AsmExchangeRole):\r
530 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack\r
531 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.\r
532\r
533 push rax\r
534 push rbx\r
535 push rcx\r
536 push rdx\r
537 push rsi\r
538 push rdi\r
539 push rbp\r
540 push r8\r
541 push r9\r
542 push r10\r
543 push r11\r
544 push r12\r
545 push r13\r
546 push r14\r
547 push r15\r
548\r
d94e5f67
JF
549 ; rsi contains MyInfo pointer\r
550 mov rsi, rcx\r
551\r
552 ; rdi contains OthersInfo pointer\r
553 mov rdi, rdx\r
554\r
d94e5f67 555 pushfq\r
d94e5f67
JF
556\r
557 ; Store the its StackPointer\r
2fba7d4e 558 mov [rsi + CPU_EXCHANGE_ROLE_INFO.StackPointer], rsp\r
d94e5f67
JF
559\r
560 ; update its switch state to STORED\r
2fba7d4e 561 mov byte [rsi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED\r
d94e5f67
JF
562\r
563WaitForOtherStored:\r
564 ; wait until the other CPU finish storing its state\r
2fba7d4e 565 cmp byte [rdi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED\r
d94e5f67
JF
566 jz OtherStored\r
567 pause\r
568 jmp WaitForOtherStored\r
569\r
570OtherStored:\r
d94e5f67
JF
571\r
572 ; load its future StackPointer\r
2fba7d4e 573 mov rsp, [rdi + CPU_EXCHANGE_ROLE_INFO.StackPointer]\r
d94e5f67
JF
574\r
575 ; update the other CPU's switch state to LOADED\r
2fba7d4e 576 mov byte [rdi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED\r
d94e5f67
JF
577\r
578WaitForOtherLoaded:\r
579 ; wait until the other CPU finish loading new state,\r
580 ; otherwise the data in stack may corrupt\r
2fba7d4e 581 cmp byte [rsi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED\r
d94e5f67
JF
582 jz OtherLoaded\r
583 pause\r
584 jmp WaitForOtherLoaded\r
585\r
586OtherLoaded:\r
587 ; since the other CPU already get the data it want, leave this procedure\r
588 popfq\r
589\r
d94e5f67
JF
590 pop r15\r
591 pop r14\r
592 pop r13\r
593 pop r12\r
594 pop r11\r
595 pop r10\r
596 pop r9\r
597 pop r8\r
598 pop rbp\r
599 pop rdi\r
600 pop rsi\r
601 pop rdx\r
602 pop rcx\r
603 pop rbx\r
604 pop rax\r
605\r
606 ret\r