lkml.org 
[lkml]   [2021]   [Jun]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC v2-fix-v2 3/3] x86/tdx: Handle port I/O
    Date
    From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>

    TDX hypervisors cannot emulate instructions directly. This
    includes port IO which is normally emulated in the hypervisor.
    All port IO instructions inside TDX trigger the #VE exception
    in the guest and would be normally emulated there.

    Also string I/O is not supported in TDX guest. So, unroll the
    string I/O operation into a loop operating on one element at
    a time. This method is similar to AMD SEV, so just extend the
    support for TDX guest platform.

    Co-developed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
    Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
    Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
    Reviewed-by: Andi Kleen <ak@linux.intel.com>
    ---
    Changes since RFC v2-fix-v1:
    * Fixed commit log to adapt to decompression support code split.

    arch/x86/include/asm/io.h | 6 ++++--
    arch/x86/kernel/tdx.c | 28 ++++++++++++++++++++++++++++
    2 files changed, 32 insertions(+), 2 deletions(-)

    diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
    index 391205dace98..e01d8bf2b37a 100644
    --- a/arch/x86/include/asm/io.h
    +++ b/arch/x86/include/asm/io.h
    @@ -310,7 +310,8 @@ static inline unsigned type in##bwl##_p(int port) \
    \
    static inline void outs##bwl(int port, const void *addr, unsigned long count) \
    { \
    - if (sev_key_active()) { \
    + if (sev_key_active() || \
    + protected_guest_has(VM_UNROLL_STRING_IO)) { \
    unsigned type *value = (unsigned type *)addr; \
    while (count) { \
    out##bwl(*value, port); \
    @@ -326,7 +327,8 @@ static inline void outs##bwl(int port, const void *addr, unsigned long count) \
    \
    static inline void ins##bwl(int port, void *addr, unsigned long count) \
    { \
    - if (sev_key_active()) { \
    + if (sev_key_active() || \
    + protected_guest_has(VM_UNROLL_STRING_IO)) { \
    unsigned type *value = (unsigned type *)addr; \
    while (count) { \
    *value = in##bwl(port); \
    diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c
    index 3410cfc8a988..48a0cc2663ea 100644
    --- a/arch/x86/kernel/tdx.c
    +++ b/arch/x86/kernel/tdx.c
    @@ -201,6 +201,31 @@ static void tdg_handle_cpuid(struct pt_regs *regs)
    regs->dx = out.r15;
    }

    +/*
    + * Since the way we fail for string case is different we cannot
    + * reuse tdx_handle_early_io().
    + */
    +static void tdg_handle_io(struct pt_regs *regs, u32 exit_qual)
    +{
    + struct tdx_hypercall_output outh;
    + int out = VE_IS_IO_OUT(exit_qual);
    + int size = VE_GET_IO_SIZE(exit_qual);
    + int port = VE_GET_PORT_NUM(exit_qual);
    + u64 mask = GENMASK(8 * size, 0);
    + bool string = VE_IS_IO_STRING(exit_qual);
    + int ret;
    +
    + /* I/O strings ops are unrolled at build time. */
    + BUG_ON(string);
    +
    + ret = __tdx_hypercall(EXIT_REASON_IO_INSTRUCTION, size, out, port,
    + regs->ax, &outh);
    + if (!out) {
    + regs->ax &= ~mask;
    + regs->ax |= (ret ? UINT_MAX : outh.r11) & mask;
    + }
    +}
    +
    unsigned long tdg_get_ve_info(struct ve_info *ve)
    {
    u64 ret;
    @@ -247,6 +272,9 @@ int tdg_handle_virtualization_exception(struct pt_regs *regs,
    case EXIT_REASON_CPUID:
    tdg_handle_cpuid(regs);
    break;
    + case EXIT_REASON_IO_INSTRUCTION:
    + tdg_handle_io(regs, ve->exit_qual);
    + break;
    default:
    pr_warn("Unexpected #VE: %lld\n", ve->exit_reason);
    return -EFAULT;
    --
    2.25.1
    \
     
     \ /
      Last update: 2021-06-08 17:41    [W:4.175 / U:2.436 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site