+;------------------------------------------------------------------------------\r
+;\r
+; Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
+;\r
+; This program and the accompanying materials are licensed and made available\r
+; under the terms and conditions of the BSD License which accompanies this\r
+; distribution. The full text of the license may be found at\r
+; http://opensource.org/licenses/bsd-license.php.\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+;------------------------------------------------------------------------------\r
+\r
+ DEFAULT REL\r
+ SECTION .text\r
+\r
+;------------------------------------------------------------------------------\r
+; Check whether we need to unroll the String I/O in SEV guest\r
+;\r
+; Return // eax (1 - unroll, 0 - no unroll)\r
+;------------------------------------------------------------------------------\r
+global ASM_PFX(SevNoRepIo)\r
+ASM_PFX(SevNoRepIo):\r
+\r
+ ; CPUID clobbers ebx, ecx and edx\r
+ push rbx\r
+ push rcx\r
+ push rdx\r
+\r
+ ; Check if we are runing under hypervisor\r
+ ; CPUID(1).ECX Bit 31\r
+ mov eax, 1\r
+ cpuid\r
+ bt ecx, 31\r
+ jnc @UseRepIo\r
+\r
+ ; Check if we have Memory encryption CPUID leaf\r
+ mov eax, 0x80000000\r
+ cpuid\r
+ cmp eax, 0x8000001f\r
+ jl @UseRepIo\r
+\r
+ ; Check for memory encryption feature:\r
+ ; CPUID Fn8000_001F[EAX] - Bit 1\r
+ ;\r
+ mov eax, 0x8000001f\r
+ cpuid\r
+ bt eax, 1\r
+ jnc @UseRepIo\r
+\r
+ ; Check if memory encryption is enabled\r
+ ; MSR_0xC0010131 - Bit 0 (SEV enabled)\r
+ ; MSR_0xC0010131 - Bit 1 (SEV-ES enabled)\r
+ mov ecx, 0xc0010131\r
+ rdmsr\r
+\r
+ ; Check for (SevEsEnabled == 0 && SevEnabled == 1)\r
+ and eax, 3\r
+ cmp eax, 1\r
+ je @SevNoRepIo_Done\r
+\r
+@UseRepIo:\r
+ xor eax, eax\r
+\r
+@SevNoRepIo_Done:\r
+ pop rdx\r
+ pop rcx\r
+ pop rbx\r
+ ret\r
+\r
+;------------------------------------------------------------------------------\r
+; VOID\r
+; EFIAPI\r
+; IoReadFifo8 (\r
+; IN UINTN Port, // rcx\r
+; IN UINTN Size, // rdx\r
+; OUT VOID *Buffer // r8\r
+; );\r
+;------------------------------------------------------------------------------\r
+global ASM_PFX(IoReadFifo8)\r
+ASM_PFX(IoReadFifo8):\r
+ xchg rcx, rdx\r
+ xchg rdi, r8 ; rdi: buffer address; r8: save rdi\r
+\r
+ ; Check if we need to unroll String I/O\r
+ call ASM_PFX(SevNoRepIo)\r
+ test eax, eax\r
+ jnz @IoReadFifo8_NoRep\r
+\r
+ cld\r
+ rep insb\r
+ jmp @IoReadFifo8_Done\r
+\r
+@IoReadFifo8_NoRep:\r
+ jrcxz @IoReadFifo8_Done\r
+\r
+@IoReadFifo8_Loop:\r
+ in al, dx\r
+ mov byte [rdi], al\r
+ inc rdi\r
+ loop @IoReadFifo8_Loop\r
+\r
+@IoReadFifo8_Done:\r
+ mov rdi, r8 ; restore rdi\r
+ ret\r
+\r
+;------------------------------------------------------------------------------\r
+; VOID\r
+; EFIAPI\r
+; IoReadFifo16 (\r
+; IN UINTN Port, // rcx\r
+; IN UINTN Size, // rdx\r
+; OUT VOID *Buffer // r8\r
+; );\r
+;------------------------------------------------------------------------------\r
+global ASM_PFX(IoReadFifo16)\r
+ASM_PFX(IoReadFifo16):\r
+ xchg rcx, rdx\r
+ xchg rdi, r8 ; rdi: buffer address; r8: save rdi\r
+\r
+ ; Check if we need to unroll String I/O\r
+ call ASM_PFX(SevNoRepIo)\r
+ test eax, eax\r
+ jnz @IoReadFifo16_NoRep\r
+\r
+ cld\r
+ rep insw\r
+ jmp @IoReadFifo16_Done\r
+\r
+@IoReadFifo16_NoRep:\r
+ jrcxz @IoReadFifo16_Done\r
+\r
+@IoReadFifo16_Loop:\r
+ in ax, dx\r
+ mov word [rdi], ax\r
+ add rdi, 2\r
+ loop @IoReadFifo16_Loop\r
+\r
+@IoReadFifo16_Done:\r
+ mov rdi, r8 ; restore rdi\r
+ ret\r
+\r
+;------------------------------------------------------------------------------\r
+; VOID\r
+; EFIAPI\r
+; IoReadFifo32 (\r
+; IN UINTN Port, // rcx\r
+; IN UINTN Size, // rdx\r
+; OUT VOID *Buffer // r8\r
+; );\r
+;------------------------------------------------------------------------------\r
+global ASM_PFX(IoReadFifo32)\r
+ASM_PFX(IoReadFifo32):\r
+ xchg rcx, rdx\r
+ xchg rdi, r8 ; rdi: buffer address; r8: save rdi\r
+\r
+ ; Check if we need to unroll String I/O\r
+ call ASM_PFX(SevNoRepIo)\r
+ test eax, eax\r
+ jnz @IoReadFifo32_NoRep\r
+\r
+ cld\r
+ rep insd\r
+ jmp @IoReadFifo32_Done\r
+\r
+@IoReadFifo32_NoRep:\r
+ jrcxz @IoReadFifo32_Done\r
+\r
+@IoReadFifo32_Loop:\r
+ in eax, dx\r
+ mov dword [rdi], eax\r
+ add rdi, 4\r
+ loop @IoReadFifo32_Loop\r
+\r
+@IoReadFifo32_Done:\r
+ mov rdi, r8 ; restore rdi\r
+ ret\r
+\r
+;------------------------------------------------------------------------------\r
+; VOID\r
+; EFIAPI\r
+; IoWriteFifo8 (\r
+; IN UINTN Port, // rcx\r
+; IN UINTN Size, // rdx\r
+; IN VOID *Buffer // r8\r
+; );\r
+;------------------------------------------------------------------------------\r
+global ASM_PFX(IoWriteFifo8)\r
+ASM_PFX(IoWriteFifo8):\r
+ xchg rcx, rdx\r
+ xchg rsi, r8 ; rsi: buffer address; r8: save rsi\r
+\r
+ ; Check if we need to unroll String I/O\r
+ call ASM_PFX(SevNoRepIo)\r
+ test eax, eax\r
+ jnz @IoWriteFifo8_NoRep\r
+\r
+ cld\r
+ rep outsb\r
+ jmp @IoWriteFifo8_Done\r
+\r
+@IoWriteFifo8_NoRep:\r
+ jrcxz @IoWriteFifo8_Done\r
+\r
+@IoWriteFifo8_Loop:\r
+ mov byte [rsi], al\r
+ out dx, al\r
+ inc rsi\r
+ loop @IoWriteFifo8_Loop\r
+\r
+@IoWriteFifo8_Done:\r
+ mov rsi, r8 ; restore rsi\r
+ ret\r
+\r
+;------------------------------------------------------------------------------\r
+; VOID\r
+; EFIAPI\r
+; IoWriteFifo16 (\r
+; IN UINTN Port, // rcx\r
+; IN UINTN Size, // rdx\r
+; IN VOID *Buffer // r8\r
+; );\r
+;------------------------------------------------------------------------------\r
+global ASM_PFX(IoWriteFifo16)\r
+ASM_PFX(IoWriteFifo16):\r
+ xchg rcx, rdx\r
+ xchg rsi, r8 ; rsi: buffer address; r8: save rsi\r
+\r
+ ; Check if we need to unroll String I/O\r
+ call ASM_PFX(SevNoRepIo)\r
+ test eax, eax\r
+ jnz @IoWriteFifo16_NoRep\r
+\r
+ cld\r
+ rep outsw\r
+ jmp @IoWriteFifo16_Done\r
+\r
+@IoWriteFifo16_NoRep:\r
+ jrcxz @IoWriteFifo16_Done\r
+\r
+@IoWriteFifo16_Loop:\r
+ mov word [rsi], ax\r
+ out dx, ax\r
+ add rsi, 2\r
+ loop @IoWriteFifo16_Loop\r
+\r
+@IoWriteFifo16_Done:\r
+ mov rsi, r8 ; restore rsi\r
+ ret\r
+\r
+;------------------------------------------------------------------------------\r
+; VOID\r
+; EFIAPI\r
+; IoWriteFifo32 (\r
+; IN UINTN Port, // rcx\r
+; IN UINTN Size, // rdx\r
+; IN VOID *Buffer // r8\r
+; );\r
+;------------------------------------------------------------------------------\r
+global ASM_PFX(IoWriteFifo32)\r
+ASM_PFX(IoWriteFifo32):\r
+ xchg rcx, rdx\r
+ xchg rsi, r8 ; rsi: buffer address; r8: save rsi\r
+\r
+ ; Check if we need to unroll String I/O\r
+ call ASM_PFX(SevNoRepIo)\r
+ test eax, eax\r
+ jnz @IoWriteFifo32_NoRep\r
+\r
+ cld\r
+ rep outsd\r
+ jmp @IoWriteFifo32_Done\r
+\r
+@IoWriteFifo32_NoRep:\r
+ jrcxz @IoWriteFifo32_Done\r
+\r
+@IoWriteFifo32_Loop:\r
+ mov dword [rsi], eax\r
+ out dx, eax\r
+ add rsi, 4\r
+ loop @IoWriteFifo32_Loop\r
+\r
+@IoWriteFifo32_Done:\r
+ mov rsi, r8 ; restore rsi\r
+ ret\r
+\r