# TITLE CpuAsm.asm: #------------------------------------------------------------------------------ #* #* Copyright 2008 - 2009, Intel Corporation #* All rights reserved. This program and the accompanying materials #* are licensed and made available under the terms and conditions of the BSD License #* which accompanies this distribution. The full text of the license may be found at #* http://opensource.org/licenses/bsd-license.php #* #* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, #* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #* #* CpuAsm.S #* #* Abstract: #* #------------------------------------------------------------------------------ #text SEGMENT #EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions # # point to the external interrupt vector table # ExternalVectorTablePtr: .byte 0, 0, 0, 0, 0, 0, 0, 0 .intel_syntax ASM_GLOBAL ASM_PFX(InitializeExternalVectorTablePtr) ASM_PFX(InitializeExternalVectorTablePtr): lea %rax, [%rip+ExternalVectorTablePtr] # save vector number mov [%rax], %rcx ret #------------------------------------------------------------------------------ # VOID # SetCodeSelector ( # UINT16 Selector # ); #------------------------------------------------------------------------------ .intel_syntax ASM_GLOBAL ASM_PFX(SetCodeSelector) ASM_PFX(SetCodeSelector): sub %rsp, 0x10 lea %rax, [%rip+setCodeSelectorLongJump] mov [%rsp], %rax mov [%rsp+4], %cx jmp fword ptr [%rsp] setCodeSelectorLongJump: add %rsp, 0x10 ret #------------------------------------------------------------------------------ # VOID # SetDataSelectors ( # UINT16 Selector # ); #------------------------------------------------------------------------------ .intel_syntax ASM_GLOBAL ASM_PFX(SetDataSelectors) ASM_PFX(SetDataSelectors): mov %ss, %cx mov %ds, %cx mov %es, %cx mov %fs, %cx mov %gs, %cx ret #---------------------------------------; # CommonInterruptEntry ; #---------------------------------------; # The follow algorithm is used for the common interrupt routine. .intel_syntax ASM_GLOBAL ASM_PFX(CommonInterruptEntry) ASM_PFX(CommonInterruptEntry): cli # # All interrupt handlers are invoked through interrupt gates, so # IF flag automatically cleared at the entry point # # # Calculate vector number # xchg %rcx, [%rsp] # get the return address of call, actually, it is the address of vector number. movzx %ecx, word ptr [%rcx] cmp %ecx, 32 # Intel reserved vector for exceptions? jae NoErrorCode push %rax lea %rax, [%rip+ASM_PFX(mErrorCodeFlag)] bt dword ptr [%rax], %ecx pop %rax jc CommonInterruptEntry_al_0000 NoErrorCode: # # Push a dummy error code on the stack # to maintain coherent stack map # push [%rsp] mov qword ptr [%rsp + 8], 0 CommonInterruptEntry_al_0000: push %rbp mov %rbp, %rsp # # Stack: # +---------------------+ <-- 16-byte aligned ensured by processor # + Old SS + # +---------------------+ # + Old RSP + # +---------------------+ # + RFlags + # +---------------------+ # + CS + # +---------------------+ # + RIP + # +---------------------+ # + Error Code + # +---------------------+ # + RCX / Vector Number + # +---------------------+ # + RBP + # +---------------------+ <-- RBP, 16-byte aligned # # # Since here the stack pointer is 16-byte aligned, so # EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 # is 16-byte aligned # #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; push %r15 push %r14 push %r13 push %r12 push %r11 push %r10 push %r9 push %r8 push %rax push qword ptr [%rbp + 8] # RCX push %rdx push %rbx push qword ptr [%rbp + 48] # RSP push qword ptr [%rbp] # RBP push %rsi push %rdi #; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero movzx %rax, word ptr [%rbp + 56] push %rax # for ss movzx %rax, word ptr [%rbp + 32] push %rax # for cs mov %rax, %ds push %rax mov %rax, %es push %rax mov %rax, %fs push %rax mov %rax, %gs push %rax mov [%rbp + 8], %rcx # save vector number #; UINT64 Rip; push qword ptr [%rbp + 24] #; UINT64 Gdtr[2], Idtr[2]; xor %rax, %rax push %rax push %rax sidt [%rsp] xchg %rax, [%rsp + 2] xchg %rax, [%rsp] xchg %rax, [%rsp + 8] xor %rax, %rax push %rax push %rax sgdt [%rsp] xchg %rax, [%rsp + 2] xchg %rax, [%rsp] xchg %rax, [%rsp + 8] #; UINT64 Ldtr, Tr; xor %rax, %rax str %ax push %rax sldt %ax push %rax #; UINT64 RFlags; push qword ptr [%rbp + 40] #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; mov %rax, %cr8 push %rax mov %rax, %cr4 or %rax, 0x208 mov %cr4, %rax push %rax mov %rax, %cr3 push %rax mov %rax, %cr2 push %rax xor %rax, %rax push %rax mov %rax, %cr0 push %rax #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; mov %rax, %dr7 push %rax #; clear Dr7 while executing debugger itself xor %rax, %rax mov %dr7, %rax mov %rax, %dr6 push %rax #; insure all status bits in dr6 are clear... xor %rax, %rax mov %dr6, %rax mov %rax, %dr3 push %rax mov %rax, %dr2 push %rax mov %rax, %dr1 push %rax mov %rax, %dr0 push %rax #; FX_SAVE_STATE_X64 FxSaveState; sub %rsp, 512 mov %rdi, %rsp .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi] #; UINT32 ExceptionData; push qword ptr [%rbp + 16] #; call into exception handler mov %rcx, [%rbp + 8] lea %rax, [%rip+ExternalVectorTablePtr] mov %eax, [%eax] mov %rax, [%rax + %rcx * 8] or %rax, %rax # NULL? je nonNullValue# #; Prepare parameter and call # mov rcx, [rbp + 8] mov %rdx, %rsp # # Per X64 calling convention, allocate maximum parameter stack space # and make sure RSP is 16-byte aligned # sub %rsp, 4 * 8 + 8 call %rax add %rsp, 4 * 8 + 8 nonNullValue: cli #; UINT64 ExceptionData; add %rsp, 8 #; FX_SAVE_STATE_X64 FxSaveState; mov %rsi, %rsp .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi] add %rsp, 512 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; pop %rax mov %dr0, %rax pop %rax mov %dr1, %rax pop %rax mov %dr2, %rax pop %rax mov %dr3, %rax #; skip restore of dr6. We cleared dr6 during the context save. add %rsp, 8 pop %rax mov %dr7, %rax #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; pop %rax mov %cr0, %rax add %rsp, 8 # not for Cr1 pop %rax mov %cr2, %rax pop %rax mov %cr3, %rax pop %rax mov %cr4, %rax pop %rax mov %cr8, %rax #; UINT64 RFlags; pop qword ptr [%rbp + 40] #; UINT64 Ldtr, Tr; #; UINT64 Gdtr[2], Idtr[2]; #; Best not let anyone mess with these particular registers... add %rsp, 48 #; UINT64 Rip; pop qword ptr [%rbp + 24] #; UINT64 Gs, Fs, Es, Ds, Cs, Ss; pop %rax # mov gs, rax ; not for gs pop %rax # mov fs, rax ; not for fs # (X64 will not use fs and gs, so we do not restore it) pop %rax mov %es, %rax pop %rax mov %ds, %rax pop qword ptr [%rbp + 32] # for cs pop qword ptr [%rbp + 56] # for ss #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; pop %rdi pop %rsi add %rsp, 8 # not for rbp pop qword ptr [%rbp + 48] # for rsp pop %rbx pop %rdx pop %rcx pop %rax pop %r8 pop %r9 pop %r10 pop %r11 pop %r12 pop %r13 pop %r14 pop %r15 mov %rsp, %rbp pop %rbp add %rsp, 16 iretq #text ENDS #END