;------------------------------------------------------------------------------
;
; Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
; Copyright (c) 2017, AMD Incorporated. All rights reserved.
;
; SPDX-License-Identifier: BSD-2-Clause-Patent
;
;------------------------------------------------------------------------------
    DEFAULT REL
    SECTION .text
;------------------------------------------------------------------------------
; Check whether we need to unroll the String I/O in SEV guest
;
; Return // eax   (1 - unroll, 0 - no unroll)
;------------------------------------------------------------------------------
global ASM_PFX(SevNoRepIo)
ASM_PFX(SevNoRepIo):
  ; CPUID clobbers ebx, ecx and edx
  push      rbx
  push      rcx
  push      rdx
  ; Check if we are runing under hypervisor
  ; CPUID(1).ECX Bit 31
  mov       eax, 1
  cpuid
  bt        ecx, 31
  jnc       @UseRepIo
  ; Check if we have Memory encryption CPUID leaf
  mov       eax, 0x80000000
  cpuid
  cmp       eax, 0x8000001f
  jl        @UseRepIo
  ; Check for memory encryption feature:
  ;  CPUID  Fn8000_001F[EAX] - Bit 1
  ;
  mov       eax,  0x8000001f
  cpuid
  bt        eax, 1
  jnc       @UseRepIo
  ; Check if memory encryption is enabled
  ;  MSR_0xC0010131 - Bit 0 (SEV enabled)
  ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
  mov       ecx, 0xc0010131
  rdmsr
  ; Check for (SevEsEnabled == 0 && SevEnabled == 1)
  and       eax, 3
  cmp       eax, 1
  je        @SevNoRepIo_Done
@UseRepIo:
  xor       eax, eax
@SevNoRepIo_Done:
  pop       rdx
  pop       rcx
  pop       rbx
  ret
;------------------------------------------------------------------------------
;  VOID
;  EFIAPI
;  IoReadFifo8 (
;    IN  UINTN                 Port,              // rcx
;    IN  UINTN                 Size,              // rdx
;    OUT VOID                  *Buffer            // r8
;    );
;------------------------------------------------------------------------------
global ASM_PFX(IoReadFifo8)
ASM_PFX(IoReadFifo8):
    xchg    rcx, rdx
    xchg    rdi, r8             ; rdi: buffer address; r8: save rdi
    ; Check if we need to unroll String I/O
    call    ASM_PFX(SevNoRepIo)
    test    eax, eax
    jnz     @IoReadFifo8_NoRep
    cld
    rep     insb
    jmp     @IoReadFifo8_Done
@IoReadFifo8_NoRep:
    jrcxz   @IoReadFifo8_Done
@IoReadFifo8_Loop:
    in      al, dx
    mov     byte [rdi], al
    inc     rdi
    loop    @IoReadFifo8_Loop
@IoReadFifo8_Done:
    mov     rdi, r8             ; restore rdi
    ret
;------------------------------------------------------------------------------
;  VOID
;  EFIAPI
;  IoReadFifo16 (
;    IN  UINTN                 Port,              // rcx
;    IN  UINTN                 Size,              // rdx
;    OUT VOID                  *Buffer            // r8
;    );
;------------------------------------------------------------------------------
global ASM_PFX(IoReadFifo16)
ASM_PFX(IoReadFifo16):
    xchg    rcx, rdx
    xchg    rdi, r8             ; rdi: buffer address; r8: save rdi
    ; Check if we need to unroll String I/O
    call    ASM_PFX(SevNoRepIo)
    test    eax, eax
    jnz     @IoReadFifo16_NoRep
    cld
    rep     insw
    jmp     @IoReadFifo16_Done
@IoReadFifo16_NoRep:
    jrcxz   @IoReadFifo16_Done
@IoReadFifo16_Loop:
    in      ax, dx
    mov     word [rdi], ax
    add     rdi, 2
    loop    @IoReadFifo16_Loop
@IoReadFifo16_Done:
    mov     rdi, r8             ; restore rdi
    ret
;------------------------------------------------------------------------------
;  VOID
;  EFIAPI
;  IoReadFifo32 (
;    IN  UINTN                 Port,              // rcx
;    IN  UINTN                 Size,              // rdx
;    OUT VOID                  *Buffer            // r8
;    );
;------------------------------------------------------------------------------
global ASM_PFX(IoReadFifo32)
ASM_PFX(IoReadFifo32):
    xchg    rcx, rdx
    xchg    rdi, r8             ; rdi: buffer address; r8: save rdi
    ; Check if we need to unroll String I/O
    call    ASM_PFX(SevNoRepIo)
    test    eax, eax
    jnz     @IoReadFifo32_NoRep
    cld
    rep     insd
    jmp     @IoReadFifo32_Done
@IoReadFifo32_NoRep:
    jrcxz   @IoReadFifo32_Done
@IoReadFifo32_Loop:
    in      eax, dx
    mov     dword [rdi], eax
    add     rdi, 4
    loop    @IoReadFifo32_Loop
@IoReadFifo32_Done:
    mov     rdi, r8             ; restore rdi
    ret
;------------------------------------------------------------------------------
;  VOID
;  EFIAPI
;  IoWriteFifo8 (
;    IN UINTN                  Port,              // rcx
;    IN UINTN                  Size,              // rdx
;    IN VOID                   *Buffer            // r8
;    );
;------------------------------------------------------------------------------
global ASM_PFX(IoWriteFifo8)
ASM_PFX(IoWriteFifo8):
    xchg    rcx, rdx
    xchg    rsi, r8             ; rsi: buffer address; r8: save rsi
    ; Check if we need to unroll String I/O
    call    ASM_PFX(SevNoRepIo)
    test    eax, eax
    jnz     @IoWriteFifo8_NoRep
    cld
    rep     outsb
    jmp     @IoWriteFifo8_Done
@IoWriteFifo8_NoRep:
    jrcxz   @IoWriteFifo8_Done
@IoWriteFifo8_Loop:
    mov     al, byte [rsi]
    out     dx, al
    inc     rsi
    loop    @IoWriteFifo8_Loop
@IoWriteFifo8_Done:
    mov     rsi, r8             ; restore rsi
    ret
;------------------------------------------------------------------------------
;  VOID
;  EFIAPI
;  IoWriteFifo16 (
;    IN UINTN                  Port,              // rcx
;    IN UINTN                  Size,              // rdx
;    IN VOID                   *Buffer            // r8
;    );
;------------------------------------------------------------------------------
global ASM_PFX(IoWriteFifo16)
ASM_PFX(IoWriteFifo16):
    xchg    rcx, rdx
    xchg    rsi, r8             ; rsi: buffer address; r8: save rsi
    ; Check if we need to unroll String I/O
    call    ASM_PFX(SevNoRepIo)
    test    eax, eax
    jnz     @IoWriteFifo16_NoRep
    cld
    rep     outsw
    jmp     @IoWriteFifo16_Done
@IoWriteFifo16_NoRep:
    jrcxz   @IoWriteFifo16_Done
@IoWriteFifo16_Loop:
    mov     ax, word [rsi]
    out     dx, ax
    add     rsi, 2
    loop    @IoWriteFifo16_Loop
@IoWriteFifo16_Done:
    mov     rsi, r8             ; restore rsi
    ret
;------------------------------------------------------------------------------
;  VOID
;  EFIAPI
;  IoWriteFifo32 (
;    IN UINTN                  Port,              // rcx
;    IN UINTN                  Size,              // rdx
;    IN VOID                   *Buffer            // r8
;    );
;------------------------------------------------------------------------------
global ASM_PFX(IoWriteFifo32)
ASM_PFX(IoWriteFifo32):
    xchg    rcx, rdx
    xchg    rsi, r8             ; rsi: buffer address; r8: save rsi
    ; Check if we need to unroll String I/O
    call    ASM_PFX(SevNoRepIo)
    test    eax, eax
    jnz     @IoWriteFifo32_NoRep
    cld
    rep     outsd
    jmp     @IoWriteFifo32_Done
@IoWriteFifo32_NoRep:
    jrcxz   @IoWriteFifo32_Done
@IoWriteFifo32_Loop:
    mov     eax, dword [rsi]
    out     dx, eax
    add     rsi, 4
    loop    @IoWriteFifo32_Loop
@IoWriteFifo32_Done:
    mov     rsi, r8             ; restore rsi
    ret