;; @file
;   This is the assembly code for transferring to control to OS S3 waking vector
;   for X64 platform
;
; Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
;
; 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.
;
;;

EXTERN mOriginalHandler:QWORD
EXTERN PageFaultHandler:PROC

    .code
    
EXTERNDEF   AsmFixAddress16:DWORD
EXTERNDEF   AsmJmpAddr32:DWORD
    
AsmTransferControl  PROC
    ; rcx S3WakingVector    :DWORD
    ; rdx AcpiLowMemoryBase :DWORD
    lea   eax, @F
    mov   r8, 2800000000h
    or    rax, r8
    push  rax
    shrd  ebx, ecx, 20
    and   ecx, 0fh          
    mov   bx, cx          
    mov   @jmp_addr, ebx
    retf
@@:
    DB    0b8h, 30h, 0      ; mov ax, 30h as selector
    mov   ds, eax
    mov   es, eax
    mov   fs, eax
    mov   gs, eax
    mov   ss, eax
    mov   rax, cr0
    mov   rbx, cr4        
    DB    66h
    and   eax, ((NOT 080000001h) AND 0ffffffffh)
    and   bl, NOT (1 SHL 5)
    mov   cr0, rax
    DB    66h
    mov   ecx, 0c0000080h
    rdmsr
    and   ah, NOT 1
    wrmsr
    mov   cr4, rbx
    DB    0eah              ; jmp far @jmp_addr
@jmp_addr DD  ?
AsmTransferControl  ENDP

AsmTransferControl32  PROC
    ; S3WakingVector    :DWORD
    ; AcpiLowMemoryBase :DWORD
    push  rbp
    mov   ebp, esp    
    DB    8dh, 05h          ;  lea   eax, AsmTransferControl16
AsmFixAddress16  DD ?
    push  28h               ; CS
    push  rax
    retf
AsmTransferControl32  ENDP

AsmTransferControl16  PROC
    DB    0b8h, 30h, 0      ; mov ax, 30h as selector
    mov   ds, ax
    mov   es, ax
    mov   fs, ax
    mov   gs, ax
    mov   ss, ax
    mov   rax, cr0          ; Get control register 0  
    DB    66h
    DB    83h, 0e0h, 0feh   ; and    eax, 0fffffffeh  ; Clear PE bit (bit #0)
    DB    0fh, 22h, 0c0h    ; mov    cr0, eax         ; Activate real mode
    DB    0eah              ; jmp far AsmJmpAddr32
AsmJmpAddr32 DD  ?
AsmTransferControl16  ENDP

PageFaultHandlerHook PROC
    push    rax                         ; save all volatile registers
    push    rcx
    push    rdx
    push    r8
    push    r9
    push    r10
    push    r11
    ; save volatile fp registers
    add     rsp, -68h
    stmxcsr [rsp + 60h]
    movdqa  [rsp + 0h], xmm0
    movdqa  [rsp + 10h], xmm1
    movdqa  [rsp + 20h], xmm2
    movdqa  [rsp + 30h], xmm3
    movdqa  [rsp + 40h], xmm4
    movdqa  [rsp + 50h], xmm5

    add     rsp, -20h
    call    PageFaultHandler
    add     rsp, 20h
    
    ; load volatile fp registers
    ldmxcsr [rsp + 60h]
    movdqa  xmm0,  [rsp + 0h]
    movdqa  xmm1,  [rsp + 10h]
    movdqa  xmm2,  [rsp + 20h]
    movdqa  xmm3,  [rsp + 30h]
    movdqa  xmm4,  [rsp + 40h]
    movdqa  xmm5,  [rsp + 50h]
    add     rsp, 68h

    test    al, al
    
    pop     r11
    pop     r10
    pop     r9
    pop     r8
    pop     rdx
    pop     rcx
    pop     rax                         ; restore all volatile registers
    jnz     @F
    jmp     mOriginalHandler
@@:
    add     rsp, 08h                    ; skip error code for PF
    iretq
PageFaultHandlerHook ENDP

    END
