]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/CpuDxe/X64/CpuAsm.S
Add CPU DXE driver for IA32 & X64 processor architectures.
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / X64 / CpuAsm.S
diff --git a/UefiCpuPkg/CpuDxe/X64/CpuAsm.S b/UefiCpuPkg/CpuDxe/X64/CpuAsm.S
new file mode 100755 (executable)
index 0000000..9d4c261
--- /dev/null
@@ -0,0 +1,363 @@
+#      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
+
+