]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
[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
537 pop rdx
538 pop rcx
539
540 NoSevEs:
541 cli ; Disable interrupt before switching to 32-bit mode
542 mov rax, [rsp + 40] ; CountTofinish
543 lock dec dword [rax] ; (*CountTofinish)--
544
545 mov r10, [rsp + 48] ; Pm16CodeSegment
546 mov rax, [rsp + 56] ; SevEsAPJumpTable
547 mov rbx, [rsp + 64] ; WakeupBuffer
548 mov rsp, r9 ; TopOfApStack
549
550 push rax ; Save SevEsAPJumpTable
551 push rbx ; Save WakeupBuffer
552 push r10 ; Save Pm16CodeSegment
553 push rcx ; Save MwaitSupport
554 push rdx ; Save ApTargetCState
555
556 lea rax, [PmEntry] ; rax <- The start address of transition code
557
558 push r8
559 push rax
560
561 ;
562 ; Clear R8 - R15, for reset, before going into 32-bit mode
563 ;
564 xor r8, r8
565 xor r9, r9
566 xor r10, r10
567 xor r11, r11
568 xor r12, r12
569 xor r13, r13
570 xor r14, r14
571 xor r15, r15
572
573 ;
574 ; Far return into 32-bit mode
575 ;
576 o64 retf
577
578 BITS 32
579 PmEntry:
580 mov eax, cr0
581 btr eax, 31 ; Clear CR0.PG
582 mov cr0, eax ; Disable paging and caches
583
584 mov ecx, 0xc0000080
585 rdmsr
586 and ah, ~ 1 ; Clear LME
587 wrmsr
588 mov eax, cr4
589 and al, ~ (1 << 5) ; Clear PAE
590 mov cr4, eax
591
592 pop edx
593 add esp, 4
594 pop ecx,
595 add esp, 4
596
597 MwaitCheck:
598 cmp cl, 1 ; Check mwait-monitor support
599 jnz HltLoop
600 mov ebx, edx ; Save C-State to ebx
601 MwaitLoop:
602 cli
603 mov eax, esp ; Set Monitor Address
604 xor ecx, ecx ; ecx = 0
605 xor edx, edx ; edx = 0
606 monitor
607 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]
608 shl eax, 4
609 mwait
610 jmp MwaitLoop
611
612 HltLoop:
613 pop edx ; PM16CodeSegment
614 add esp, 4
615 pop ebx ; WakeupBuffer
616 add esp, 4
617 pop eax ; SevEsAPJumpTable
618 add esp, 4
619 cmp eax, 0 ; Check for SEV-ES
620 je DoHlt
621
622 cli
623 ;
624 ; SEV-ES is enabled, use VMGEXIT (GHCB information already
625 ; set by caller)
626 ;
627 BITS 64
628 rep vmmcall
629 BITS 32
630
631 ;
632 ; Back from VMGEXIT AP_HLT_LOOP
633 ; Push the FLAGS/CS/IP values to use
634 ;
635 push word 0x0002 ; EFLAGS
636 xor ecx, ecx
637 mov cx, [eax + 2] ; CS
638 push cx
639 mov cx, [eax] ; IP
640 push cx
641 push word 0x0000 ; For alignment, will be discarded
642
643 push edx
644 push ebx
645
646 mov edx, esi ; Restore RDX reset value
647
648 retf
649
650 DoHlt:
651 cli
652 hlt
653 jmp DoHlt
654
655 BITS 64
656 AsmRelocateApLoopEnd:
657
658 ;-------------------------------------------------------------------------------------
659 ; AsmGetAddressMap (&AddressMap);
660 ;-------------------------------------------------------------------------------------
661 global ASM_PFX(AsmGetAddressMap)
662 ASM_PFX(AsmGetAddressMap):
663 lea rax, [ASM_PFX(RendezvousFunnelProc)]
664 mov qword [rcx], rax
665 mov qword [rcx + 8h], LongModeStart - RendezvousFunnelProcStart
666 mov qword [rcx + 10h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
667 lea rax, [ASM_PFX(AsmRelocateApLoop)]
668 mov qword [rcx + 18h], rax
669 mov qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
670 mov qword [rcx + 28h], Flat32Start - RendezvousFunnelProcStart
671 mov qword [rcx + 30h], SwitchToRealProcEnd - SwitchToRealProcStart ; SwitchToRealSize
672 mov qword [rcx + 38h], SwitchToRealProcStart - RendezvousFunnelProcStart ; SwitchToRealOffset
673 mov qword [rcx + 40h], SwitchToRealProcStart - Flat32Start ; SwitchToRealNoNxOffset
674 mov qword [rcx + 48h], PM16Mode - RendezvousFunnelProcStart ; SwitchToRealPM16ModeOffset
675 mov qword [rcx + 50h], SwitchToRealProcEnd - PM16Mode ; SwitchToRealPM16ModeSize
676 ret
677
678 ;-------------------------------------------------------------------------------------
679 ;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
680 ;about to become an AP. It switches its stack with the current AP.
681 ;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
682 ;-------------------------------------------------------------------------------------
683 global ASM_PFX(AsmExchangeRole)
684 ASM_PFX(AsmExchangeRole):
685 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
686 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
687
688 push rax
689 push rbx
690 push rcx
691 push rdx
692 push rsi
693 push rdi
694 push rbp
695 push r8
696 push r9
697 push r10
698 push r11
699 push r12
700 push r13
701 push r14
702 push r15
703
704 mov rax, cr0
705 push rax
706
707 mov rax, cr4
708 push rax
709
710 ; rsi contains MyInfo pointer
711 mov rsi, rcx
712
713 ; rdi contains OthersInfo pointer
714 mov rdi, rdx
715
716 ;Store EFLAGS, GDTR and IDTR regiter to stack
717 pushfq
718 sgdt [rsi + 16]
719 sidt [rsi + 26]
720
721 ; Store the its StackPointer
722 mov [rsi + 8], rsp
723
724 ; update its switch state to STORED
725 mov byte [rsi], CPU_SWITCH_STATE_STORED
726
727 WaitForOtherStored:
728 ; wait until the other CPU finish storing its state
729 cmp byte [rdi], CPU_SWITCH_STATE_STORED
730 jz OtherStored
731 pause
732 jmp WaitForOtherStored
733
734 OtherStored:
735 ; Since another CPU already stored its state, load them
736 ; load GDTR value
737 lgdt [rdi + 16]
738
739 ; load IDTR value
740 lidt [rdi + 26]
741
742 ; load its future StackPointer
743 mov rsp, [rdi + 8]
744
745 ; update the other CPU's switch state to LOADED
746 mov byte [rdi], CPU_SWITCH_STATE_LOADED
747
748 WaitForOtherLoaded:
749 ; wait until the other CPU finish loading new state,
750 ; otherwise the data in stack may corrupt
751 cmp byte [rsi], CPU_SWITCH_STATE_LOADED
752 jz OtherLoaded
753 pause
754 jmp WaitForOtherLoaded
755
756 OtherLoaded:
757 ; since the other CPU already get the data it want, leave this procedure
758 popfq
759
760 pop rax
761 mov cr4, rax
762
763 pop rax
764 mov cr0, rax
765
766 pop r15
767 pop r14
768 pop r13
769 pop r12
770 pop r11
771 pop r10
772 pop r9
773 pop r8
774 pop rbp
775 pop rdi
776 pop rsi
777 pop rdx
778 pop rcx
779 pop rbx
780 pop rax
781
782 ret