]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
UefiCpuPkg/MpInitLib: Set the SW exit fields when performing VMGEXIT
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / X64 / MpFuncs.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
3 ; SPDX-License-Identifier: BSD-2-Clause-Patent
4 ;
5 ; Module Name:
6 ;
7 ; MpFuncs.nasm
8 ;
9 ; Abstract:
10 ;
11 ; This is the assembly code for MP support
12 ;
13 ;-------------------------------------------------------------------------------
14
15 %include "MpEqu.inc"
16 extern ASM_PFX(InitializeFloatingPointUnits)
17
18 DEFAULT REL
19
20 SECTION .text
21
22 ;-------------------------------------------------------------------------------------
23 ;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
24 ;procedure serializes all the AP processors through an Init sequence. It must be
25 ;noted that APs arrive here very raw...ie: real mode, no stack.
26 ;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
27 ;IS IN MACHINE CODE.
28 ;-------------------------------------------------------------------------------------
29 global ASM_PFX(RendezvousFunnelProc)
30 ASM_PFX(RendezvousFunnelProc):
31 RendezvousFunnelProcStart:
32 ; At this point CS = 0x(vv00) and ip= 0x0.
33 ; Save BIST information to ebp firstly
34
35 BITS 16
36 mov ebp, eax ; Save BIST information
37
38 mov ax, cs
39 mov ds, ax
40 mov es, ax
41 mov ss, ax
42 xor ax, ax
43 mov fs, ax
44 mov gs, ax
45
46 mov si, BufferStartLocation
47 mov ebx, [si]
48
49 mov si, DataSegmentLocation
50 mov edx, [si]
51
52 ;
53 ; Get start address of 32-bit code in low memory (<1MB)
54 ;
55 mov edi, ModeTransitionMemoryLocation
56
57 mov si, GdtrLocation
58 o32 lgdt [cs:si]
59
60 mov si, IdtrLocation
61 o32 lidt [cs:si]
62
63 ;
64 ; Switch to protected mode
65 ;
66 mov eax, cr0 ; Get control register 0
67 or eax, 000000003h ; Set PE bit (bit #0) & MP
68 mov cr0, eax
69
70 ; Switch to 32-bit code (>1MB)
71 o32 jmp far [cs:di]
72
73 ;
74 ; Following code must be copied to memory with type of EfiBootServicesCode.
75 ; This is required if NX is enabled for EfiBootServicesCode of memory.
76 ;
77 BITS 32
78 Flat32Start: ; protected mode entry point
79 mov ds, dx
80 mov es, dx
81 mov fs, dx
82 mov gs, dx
83 mov ss, dx
84
85 ;
86 ; Enable execute disable bit
87 ;
88 mov esi, EnableExecuteDisableLocation
89 cmp byte [ebx + esi], 0
90 jz SkipEnableExecuteDisableBit
91
92 mov ecx, 0c0000080h ; EFER MSR number
93 rdmsr ; Read EFER
94 bts eax, 11 ; Enable Execute Disable Bit
95 wrmsr ; Write EFER
96
97 SkipEnableExecuteDisableBit:
98 ;
99 ; Enable PAE
100 ;
101 mov eax, cr4
102 bts eax, 5
103
104 mov esi, Enable5LevelPagingLocation
105 cmp byte [ebx + esi], 0
106 jz SkipEnable5LevelPaging
107
108 ;
109 ; Enable 5 Level Paging
110 ;
111 bts eax, 12 ; Set LA57=1.
112
113 SkipEnable5LevelPaging:
114
115 mov cr4, eax
116
117 ;
118 ; Load page table
119 ;
120 mov esi, Cr3Location ; Save CR3 in ecx
121 mov ecx, [ebx + esi]
122 mov cr3, ecx ; Load CR3
123
124 ;
125 ; Enable long mode
126 ;
127 mov ecx, 0c0000080h ; EFER MSR number
128 rdmsr ; Read EFER
129 bts eax, 8 ; Set LME=1
130 wrmsr ; Write EFER
131
132 ;
133 ; Enable paging
134 ;
135 mov eax, cr0 ; Read CR0
136 bts eax, 31 ; Set PG=1
137 mov cr0, eax ; Write CR0
138
139 ;
140 ; Far jump to 64-bit code
141 ;
142 mov edi, ModeHighMemoryLocation
143 add edi, ebx
144 jmp far [edi]
145
146 BITS 64
147 LongModeStart:
148 mov esi, ebx
149 lea edi, [esi + InitFlagLocation]
150 cmp qword [edi], 1 ; ApInitConfig
151 jnz GetApicId
152
153 ; Increment the number of APs executing here as early as possible
154 ; This is decremented in C code when AP is finished executing
155 mov edi, esi
156 add edi, NumApsExecutingLocation
157 lock inc dword [edi]
158
159 ; AP init
160 mov edi, esi
161 add edi, LockLocation
162 mov rax, NotVacantFlag
163
164 TestLock:
165 xchg qword [edi], rax
166 cmp rax, NotVacantFlag
167 jz TestLock
168
169 lea ecx, [esi + ApIndexLocation]
170 inc dword [ecx]
171 mov ebx, [ecx]
172
173 Releaselock:
174 mov rax, VacantFlag
175 xchg qword [edi], rax
176 ; program stack
177 mov edi, esi
178 add edi, StackSizeLocation
179 mov eax, dword [edi]
180 mov ecx, ebx
181 inc ecx
182 mul ecx ; EAX = StackSize * (CpuNumber + 1)
183 mov edi, esi
184 add edi, StackStartAddressLocation
185 add rax, qword [edi]
186 mov rsp, rax
187
188 lea edi, [esi + SevEsIsEnabledLocation]
189 cmp byte [edi], 1 ; SevEsIsEnabled
190 jne CProcedureInvoke
191
192 ;
193 ; program GHCB
194 ; Each page after the GHCB is a per-CPU page, so the calculation programs
195 ; a GHCB to be every 8KB.
196 ;
197 mov eax, SIZE_4KB
198 shl eax, 1 ; EAX = SIZE_4K * 2
199 mov ecx, ebx
200 mul ecx ; EAX = SIZE_4K * 2 * CpuNumber
201 mov edi, esi
202 add edi, GhcbBaseLocation
203 add rax, qword [edi]
204 mov rdx, rax
205 shr rdx, 32
206 mov rcx, 0xc0010130
207 wrmsr
208 jmp CProcedureInvoke
209
210 GetApicId:
211 lea edi, [esi + SevEsIsEnabledLocation]
212 cmp byte [edi], 1 ; SevEsIsEnabled
213 jne DoCpuid
214
215 ;
216 ; Since we don't have a stack yet, we can't take a #VC
217 ; exception. Use the GHCB protocol to perform the CPUID
218 ; calls.
219 ;
220 mov rcx, 0xc0010130
221 rdmsr
222 shl rdx, 32
223 or rax, rdx
224 mov rdi, rax ; RDI now holds the original GHCB GPA
225
226 mov rdx, 0 ; CPUID function 0
227 mov rax, 0 ; RAX register requested
228 or rax, 4
229 wrmsr
230 rep vmmcall
231 rdmsr
232 cmp edx, 0bh
233 jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOPOLOGY
234
235 mov rdx, 0bh ; CPUID function 0x0b
236 mov rax, 040000000h ; RBX register requested
237 or rax, 4
238 wrmsr
239 rep vmmcall
240 rdmsr
241 test edx, 0ffffh
242 jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero
243
244 mov rdx, 0bh ; CPUID function 0x0b
245 mov rax, 0c0000000h ; RDX register requested
246 or rax, 4
247 wrmsr
248 rep vmmcall
249 rdmsr
250
251 ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX
252 jmp RestoreGhcb
253
254 NoX2ApicSevEs:
255 ; Processor is not x2APIC capable, so get 8-bit APIC ID
256 mov rdx, 1 ; CPUID function 1
257 mov rax, 040000000h ; RBX register requested
258 or rax, 4
259 wrmsr
260 rep vmmcall
261 rdmsr
262 shr edx, 24
263
264 RestoreGhcb:
265 mov rbx, rdx ; Save x2APIC/APIC ID
266
267 mov rdx, rdi ; RDI holds the saved GHCB GPA
268 shr rdx, 32
269 mov eax, edi
270 wrmsr
271
272 mov rdx, rbx
273
274 ; x2APIC ID or APIC ID is in EDX
275 jmp GetProcessorNumber
276
277 DoCpuid:
278 mov eax, 0
279 cpuid
280 cmp eax, 0bh
281 jb NoX2Apic ; CPUID level below CPUID_EXTENDED_TOPOLOGY
282
283 mov eax, 0bh
284 xor ecx, ecx
285 cpuid
286 test ebx, 0ffffh
287 jz NoX2Apic ; CPUID.0BH:EBX[15:0] is zero
288
289 ; Processor is x2APIC capable; 32-bit x2APIC ID is already in EDX
290 jmp GetProcessorNumber
291
292 NoX2Apic:
293 ; Processor is not x2APIC capable, so get 8-bit APIC ID
294 mov eax, 1
295 cpuid
296 shr ebx, 24
297 mov edx, ebx
298
299 GetProcessorNumber:
300 ;
301 ; Get processor number for this AP
302 ; Note that BSP may become an AP due to SwitchBsp()
303 ;
304 xor ebx, ebx
305 lea eax, [esi + CpuInfoLocation]
306 mov edi, [eax]
307
308 GetNextProcNumber:
309 cmp dword [edi], edx ; APIC ID match?
310 jz ProgramStack
311 add edi, 20
312 inc ebx
313 jmp GetNextProcNumber
314
315 ProgramStack:
316 mov rsp, qword [edi + 12]
317
318 CProcedureInvoke:
319 push rbp ; Push BIST data at top of AP stack
320 xor rbp, rbp ; Clear ebp for call stack trace
321 push rbp
322 mov rbp, rsp
323
324 mov rax, qword [esi + InitializeFloatingPointUnitsAddress]
325 sub rsp, 20h
326 call rax ; Call assembly function to initialize FPU per UEFI spec
327 add rsp, 20h
328
329 mov edx, ebx ; edx is ApIndex
330 mov ecx, esi
331 add ecx, LockLocation ; rcx is address of exchange info data buffer
332
333 mov edi, esi
334 add edi, ApProcedureLocation
335 mov rax, qword [edi]
336
337 sub rsp, 20h
338 call rax ; Invoke C function
339 add rsp, 20h
340 jmp $ ; Should never reach here
341
342 RendezvousFunnelProcEnd:
343
344 ;-------------------------------------------------------------------------------------
345 ;SwitchToRealProc procedure follows.
346 ;ALSO THIS PROCEDURE IS EXECUTED BY APs TRANSITIONING TO 16 BIT MODE. HENCE THIS PROC
347 ;IS IN MACHINE CODE.
348 ; SwitchToRealProc (UINTN BufferStart, UINT16 Code16, UINT16 Code32, UINTN StackStart)
349 ; rcx - Buffer Start
350 ; rdx - Code16 Selector Offset
351 ; r8 - Code32 Selector Offset
352 ; r9 - Stack Start
353 ;-------------------------------------------------------------------------------------
354 global ASM_PFX(SwitchToRealProc)
355 ASM_PFX(SwitchToRealProc):
356 SwitchToRealProcStart:
357 BITS 64
358 cli
359
360 ;
361 ; Get RDX reset value before changing stacks since the
362 ; new stack won't be able to accomodate a #VC exception.
363 ;
364 push rax
365 push rbx
366 push rcx
367 push rdx
368
369 mov rax, 1
370 cpuid
371 mov rsi, rax ; Save off the reset value for RDX
372
373 pop rdx
374 pop rcx
375 pop rbx
376 pop rax
377
378 ;
379 ; Establish stack below 1MB
380 ;
381 mov rsp, r9
382
383 ;
384 ; Push ultimate Reset Vector onto the stack
385 ;
386 mov rax, rcx
387 shr rax, 4
388 push word 0x0002 ; RFLAGS
389 push ax ; CS
390 push word 0x0000 ; RIP
391 push word 0x0000 ; For alignment, will be discarded
392
393 ;
394 ; Get address of "16-bit operand size" label
395 ;
396 lea rbx, [PM16Mode]
397
398 ;
399 ; Push addresses used to change to compatibility mode
400 ;
401 lea rax, [CompatMode]
402 push r8
403 push rax
404
405 ;
406 ; Clear R8 - R15, for reset, before going into 32-bit mode
407 ;
408 xor r8, r8
409 xor r9, r9
410 xor r10, r10
411 xor r11, r11
412 xor r12, r12
413 xor r13, r13
414 xor r14, r14
415 xor r15, r15
416
417 ;
418 ; Far return into 32-bit mode
419 ;
420 o64 retf
421
422 BITS 32
423 CompatMode:
424 ;
425 ; Set up stack to prepare for exiting protected mode
426 ;
427 push edx ; Code16 CS
428 push ebx ; PM16Mode label address
429
430 ;
431 ; Disable paging
432 ;
433 mov eax, cr0 ; Read CR0
434 btr eax, 31 ; Set PG=0
435 mov cr0, eax ; Write CR0
436
437 ;
438 ; Disable long mode
439 ;
440 mov ecx, 0c0000080h ; EFER MSR number
441 rdmsr ; Read EFER
442 btr eax, 8 ; Set LME=0
443 wrmsr ; Write EFER
444
445 ;
446 ; Disable PAE
447 ;
448 mov eax, cr4 ; Read CR4
449 btr eax, 5 ; Set PAE=0
450 mov cr4, eax ; Write CR4
451
452 mov edx, esi ; Restore RDX reset value
453
454 ;
455 ; Switch to 16-bit operand size
456 ;
457 retf
458
459 BITS 16
460 ;
461 ; At entry to this label
462 ; - RDX will have its reset value
463 ; - On the top of the stack
464 ; - Alignment data (two bytes) to be discarded
465 ; - IP for Real Mode (two bytes)
466 ; - CS for Real Mode (two bytes)
467 ;
468 ; This label is also used with AsmRelocateApLoop. During MP finalization,
469 ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of
470 ; the WakeupBuffer, allowing a parked AP to be booted by an OS.
471 ;
472 PM16Mode:
473 mov eax, cr0 ; Read CR0
474 btr eax, 0 ; Set PE=0
475 mov cr0, eax ; Write CR0
476
477 pop ax ; Discard alignment data
478
479 ;
480 ; Clear registers (except RDX and RSP) before going into 16-bit mode
481 ;
482 xor eax, eax
483 xor ebx, ebx
484 xor ecx, ecx
485 xor esi, esi
486 xor edi, edi
487 xor ebp, ebp
488
489 iret
490
491 SwitchToRealProcEnd:
492
493 ;-------------------------------------------------------------------------------------
494 ; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);
495 ;-------------------------------------------------------------------------------------
496 global ASM_PFX(AsmRelocateApLoop)
497 ASM_PFX(AsmRelocateApLoop):
498 AsmRelocateApLoopStart:
499 BITS 64
500 cmp qword [rsp + 56], 0 ; SevEsAPJumpTable
501 je NoSevEs
502
503 ;
504 ; Perform some SEV-ES related setup before leaving 64-bit mode
505 ;
506 push rcx
507 push rdx
508
509 ;
510 ; Get the RDX reset value using CPUID
511 ;
512 mov rax, 1
513 cpuid
514 mov rsi, rax ; Save off the reset value for RDX
515
516 ;
517 ; Prepare the GHCB for the AP_HLT_LOOP VMGEXIT call
518 ; - Must be done while in 64-bit long mode so that writes to
519 ; the GHCB memory will be unencrypted.
520 ; - No NAE events can be generated once this is set otherwise
521 ; the AP_RESET_HOLD SW_EXITCODE will be overwritten.
522 ;
523 mov rcx, 0xc0010130
524 rdmsr ; Retrieve current GHCB address
525 shl rdx, 32
526 or rdx, rax
527
528 mov rdi, rdx
529 xor rax, rax
530 mov rcx, 0x800
531 shr rcx, 3
532 rep stosq ; Clear the GHCB
533
534 mov rax, 0x80000004 ; VMGEXIT AP_RESET_HOLD
535 mov [rdx + 0x390], rax
536 mov rax, 114 ; Set SwExitCode valid bit
537 bts [rdx + 0x3f0], rax
538 inc rax ; Set SwExitInfo1 valid bit
539 bts [rdx + 0x3f0], rax
540 inc rax ; Set SwExitInfo2 valid bit
541 bts [rdx + 0x3f0], rax
542
543 pop rdx
544 pop rcx
545
546 NoSevEs:
547 cli ; Disable interrupt before switching to 32-bit mode
548 mov rax, [rsp + 40] ; CountTofinish
549 lock dec dword [rax] ; (*CountTofinish)--
550
551 mov r10, [rsp + 48] ; Pm16CodeSegment
552 mov rax, [rsp + 56] ; SevEsAPJumpTable
553 mov rbx, [rsp + 64] ; WakeupBuffer
554 mov rsp, r9 ; TopOfApStack
555
556 push rax ; Save SevEsAPJumpTable
557 push rbx ; Save WakeupBuffer
558 push r10 ; Save Pm16CodeSegment
559 push rcx ; Save MwaitSupport
560 push rdx ; Save ApTargetCState
561
562 lea rax, [PmEntry] ; rax <- The start address of transition code
563
564 push r8
565 push rax
566
567 ;
568 ; Clear R8 - R15, for reset, before going into 32-bit mode
569 ;
570 xor r8, r8
571 xor r9, r9
572 xor r10, r10
573 xor r11, r11
574 xor r12, r12
575 xor r13, r13
576 xor r14, r14
577 xor r15, r15
578
579 ;
580 ; Far return into 32-bit mode
581 ;
582 o64 retf
583
584 BITS 32
585 PmEntry:
586 mov eax, cr0
587 btr eax, 31 ; Clear CR0.PG
588 mov cr0, eax ; Disable paging and caches
589
590 mov ecx, 0xc0000080
591 rdmsr
592 and ah, ~ 1 ; Clear LME
593 wrmsr
594 mov eax, cr4
595 and al, ~ (1 << 5) ; Clear PAE
596 mov cr4, eax
597
598 pop edx
599 add esp, 4
600 pop ecx,
601 add esp, 4
602
603 MwaitCheck:
604 cmp cl, 1 ; Check mwait-monitor support
605 jnz HltLoop
606 mov ebx, edx ; Save C-State to ebx
607 MwaitLoop:
608 cli
609 mov eax, esp ; Set Monitor Address
610 xor ecx, ecx ; ecx = 0
611 xor edx, edx ; edx = 0
612 monitor
613 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]
614 shl eax, 4
615 mwait
616 jmp MwaitLoop
617
618 HltLoop:
619 pop edx ; PM16CodeSegment
620 add esp, 4
621 pop ebx ; WakeupBuffer
622 add esp, 4
623 pop eax ; SevEsAPJumpTable
624 add esp, 4
625 cmp eax, 0 ; Check for SEV-ES
626 je DoHlt
627
628 cli
629 ;
630 ; SEV-ES is enabled, use VMGEXIT (GHCB information already
631 ; set by caller)
632 ;
633 BITS 64
634 rep vmmcall
635 BITS 32
636
637 ;
638 ; Back from VMGEXIT AP_HLT_LOOP
639 ; Push the FLAGS/CS/IP values to use
640 ;
641 push word 0x0002 ; EFLAGS
642 xor ecx, ecx
643 mov cx, [eax + 2] ; CS
644 push cx
645 mov cx, [eax] ; IP
646 push cx
647 push word 0x0000 ; For alignment, will be discarded
648
649 push edx
650 push ebx
651
652 mov edx, esi ; Restore RDX reset value
653
654 retf
655
656 DoHlt:
657 cli
658 hlt
659 jmp DoHlt
660
661 BITS 64
662 AsmRelocateApLoopEnd:
663
664 ;-------------------------------------------------------------------------------------
665 ; AsmGetAddressMap (&AddressMap);
666 ;-------------------------------------------------------------------------------------
667 global ASM_PFX(AsmGetAddressMap)
668 ASM_PFX(AsmGetAddressMap):
669 lea rax, [ASM_PFX(RendezvousFunnelProc)]
670 mov qword [rcx], rax
671 mov qword [rcx + 8h], LongModeStart - RendezvousFunnelProcStart
672 mov qword [rcx + 10h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
673 lea rax, [ASM_PFX(AsmRelocateApLoop)]
674 mov qword [rcx + 18h], rax
675 mov qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
676 mov qword [rcx + 28h], Flat32Start - RendezvousFunnelProcStart
677 mov qword [rcx + 30h], SwitchToRealProcEnd - SwitchToRealProcStart ; SwitchToRealSize
678 mov qword [rcx + 38h], SwitchToRealProcStart - RendezvousFunnelProcStart ; SwitchToRealOffset
679 mov qword [rcx + 40h], SwitchToRealProcStart - Flat32Start ; SwitchToRealNoNxOffset
680 mov qword [rcx + 48h], PM16Mode - RendezvousFunnelProcStart ; SwitchToRealPM16ModeOffset
681 mov qword [rcx + 50h], SwitchToRealProcEnd - PM16Mode ; SwitchToRealPM16ModeSize
682 ret
683
684 ;-------------------------------------------------------------------------------------
685 ;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
686 ;about to become an AP. It switches its stack with the current AP.
687 ;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
688 ;-------------------------------------------------------------------------------------
689 global ASM_PFX(AsmExchangeRole)
690 ASM_PFX(AsmExchangeRole):
691 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
692 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
693
694 push rax
695 push rbx
696 push rcx
697 push rdx
698 push rsi
699 push rdi
700 push rbp
701 push r8
702 push r9
703 push r10
704 push r11
705 push r12
706 push r13
707 push r14
708 push r15
709
710 mov rax, cr0
711 push rax
712
713 mov rax, cr4
714 push rax
715
716 ; rsi contains MyInfo pointer
717 mov rsi, rcx
718
719 ; rdi contains OthersInfo pointer
720 mov rdi, rdx
721
722 ;Store EFLAGS, GDTR and IDTR regiter to stack
723 pushfq
724 sgdt [rsi + 16]
725 sidt [rsi + 26]
726
727 ; Store the its StackPointer
728 mov [rsi + 8], rsp
729
730 ; update its switch state to STORED
731 mov byte [rsi], CPU_SWITCH_STATE_STORED
732
733 WaitForOtherStored:
734 ; wait until the other CPU finish storing its state
735 cmp byte [rdi], CPU_SWITCH_STATE_STORED
736 jz OtherStored
737 pause
738 jmp WaitForOtherStored
739
740 OtherStored:
741 ; Since another CPU already stored its state, load them
742 ; load GDTR value
743 lgdt [rdi + 16]
744
745 ; load IDTR value
746 lidt [rdi + 26]
747
748 ; load its future StackPointer
749 mov rsp, [rdi + 8]
750
751 ; update the other CPU's switch state to LOADED
752 mov byte [rdi], CPU_SWITCH_STATE_LOADED
753
754 WaitForOtherLoaded:
755 ; wait until the other CPU finish loading new state,
756 ; otherwise the data in stack may corrupt
757 cmp byte [rsi], CPU_SWITCH_STATE_LOADED
758 jz OtherLoaded
759 pause
760 jmp WaitForOtherLoaded
761
762 OtherLoaded:
763 ; since the other CPU already get the data it want, leave this procedure
764 popfq
765
766 pop rax
767 mov cr4, rax
768
769 pop rax
770 mov cr0, rax
771
772 pop r15
773 pop r14
774 pop r13
775 pop r12
776 pop r11
777 pop r10
778 pop r9
779 pop r8
780 pop rbp
781 pop rdi
782 pop rsi
783 pop rdx
784 pop rcx
785 pop rbx
786 pop rax
787
788 ret