Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  * AMD Memory Encryption Support
0004  *
0005  * Copyright (C) 2017 Advanced Micro Devices, Inc.
0006  *
0007  * Author: Tom Lendacky <thomas.lendacky@amd.com>
0008  */
0009 
0010 #include <linux/linkage.h>
0011 
0012 #include <asm/processor-flags.h>
0013 #include <asm/msr.h>
0014 #include <asm/asm-offsets.h>
0015 
0016     .text
0017     .code32
0018 SYM_FUNC_START(get_sev_encryption_bit)
0019     xor %eax, %eax
0020 
0021 #ifdef CONFIG_AMD_MEM_ENCRYPT
0022     push    %ebx
0023     push    %ecx
0024     push    %edx
0025 
0026     movl    $0x80000000, %eax   /* CPUID to check the highest leaf */
0027     cpuid
0028     cmpl    $0x8000001f, %eax   /* See if 0x8000001f is available */
0029     jb  .Lno_sev
0030 
0031     /*
0032      * Check for the SEV feature:
0033      *   CPUID Fn8000_001F[EAX] - Bit 1
0034      *   CPUID Fn8000_001F[EBX] - Bits 5:0
0035      *     Pagetable bit position used to indicate encryption
0036      */
0037     movl    $0x8000001f, %eax
0038     cpuid
0039     bt  $1, %eax        /* Check if SEV is available */
0040     jnc .Lno_sev
0041 
0042     movl    $MSR_AMD64_SEV, %ecx    /* Read the SEV MSR */
0043     rdmsr
0044     bt  $MSR_AMD64_SEV_ENABLED_BIT, %eax    /* Check if SEV is active */
0045     jnc .Lno_sev
0046 
0047     movl    %ebx, %eax
0048     andl    $0x3f, %eax     /* Return the encryption bit location */
0049     jmp .Lsev_exit
0050 
0051 .Lno_sev:
0052     xor %eax, %eax
0053 
0054 .Lsev_exit:
0055     pop %edx
0056     pop %ecx
0057     pop %ebx
0058 
0059 #endif  /* CONFIG_AMD_MEM_ENCRYPT */
0060 
0061     RET
0062 SYM_FUNC_END(get_sev_encryption_bit)
0063 
0064 /**
0065  * sev_es_req_cpuid - Request a CPUID value from the Hypervisor using
0066  *            the GHCB MSR protocol
0067  *
0068  * @%eax:   Register to request (0=EAX, 1=EBX, 2=ECX, 3=EDX)
0069  * @%edx:   CPUID Function
0070  *
0071  * Returns 0 in %eax on success, non-zero on failure
0072  * %edx returns CPUID value on success
0073  */
0074 SYM_CODE_START_LOCAL(sev_es_req_cpuid)
0075     shll    $30, %eax
0076     orl     $0x00000004, %eax
0077     movl    $MSR_AMD64_SEV_ES_GHCB, %ecx
0078     wrmsr
0079     rep; vmmcall        # VMGEXIT
0080     rdmsr
0081 
0082     /* Check response */
0083     movl    %eax, %ecx
0084     andl    $0x3ffff000, %ecx   # Bits [12-29] MBZ
0085     jnz 2f
0086 
0087     /* Check return code */
0088     andl    $0xfff, %eax
0089     cmpl    $5, %eax
0090     jne 2f
0091 
0092     /* All good - return success */
0093     xorl    %eax, %eax
0094 1:
0095     RET
0096 2:
0097     movl    $-1, %eax
0098     jmp 1b
0099 SYM_CODE_END(sev_es_req_cpuid)
0100 
0101 SYM_CODE_START(startup32_vc_handler)
0102     pushl   %eax
0103     pushl   %ebx
0104     pushl   %ecx
0105     pushl   %edx
0106 
0107     /* Keep CPUID function in %ebx */
0108     movl    %eax, %ebx
0109 
0110     /* Check if error-code == SVM_EXIT_CPUID */
0111     cmpl    $0x72, 16(%esp)
0112     jne .Lfail
0113 
0114     movl    $0, %eax        # Request CPUID[fn].EAX
0115     movl    %ebx, %edx      # CPUID fn
0116     call    sev_es_req_cpuid    # Call helper
0117     testl   %eax, %eax      # Check return code
0118     jnz .Lfail
0119     movl    %edx, 12(%esp)      # Store result
0120 
0121     movl    $1, %eax        # Request CPUID[fn].EBX
0122     movl    %ebx, %edx      # CPUID fn
0123     call    sev_es_req_cpuid    # Call helper
0124     testl   %eax, %eax      # Check return code
0125     jnz .Lfail
0126     movl    %edx, 8(%esp)       # Store result
0127 
0128     movl    $2, %eax        # Request CPUID[fn].ECX
0129     movl    %ebx, %edx      # CPUID fn
0130     call    sev_es_req_cpuid    # Call helper
0131     testl   %eax, %eax      # Check return code
0132     jnz .Lfail
0133     movl    %edx, 4(%esp)       # Store result
0134 
0135     movl    $3, %eax        # Request CPUID[fn].EDX
0136     movl    %ebx, %edx      # CPUID fn
0137     call    sev_es_req_cpuid    # Call helper
0138     testl   %eax, %eax      # Check return code
0139     jnz .Lfail
0140     movl    %edx, 0(%esp)       # Store result
0141 
0142     /*
0143      * Sanity check CPUID results from the Hypervisor. See comment in
0144      * do_vc_no_ghcb() for more details on why this is necessary.
0145      */
0146 
0147     /* Fail if SEV leaf not available in CPUID[0x80000000].EAX */
0148     cmpl    $0x80000000, %ebx
0149     jne     .Lcheck_sev
0150     cmpl    $0x8000001f, 12(%esp)
0151     jb      .Lfail
0152     jmp     .Ldone
0153 
0154 .Lcheck_sev:
0155     /* Fail if SEV bit not set in CPUID[0x8000001f].EAX[1] */
0156     cmpl    $0x8000001f, %ebx
0157     jne     .Ldone
0158     btl     $1, 12(%esp)
0159     jnc     .Lfail
0160 
0161 .Ldone:
0162     popl    %edx
0163     popl    %ecx
0164     popl    %ebx
0165     popl    %eax
0166 
0167     /* Remove error code */
0168     addl    $4, %esp
0169 
0170     /* Jump over CPUID instruction */
0171     addl    $2, (%esp)
0172 
0173     iret
0174 .Lfail:
0175     /* Send terminate request to Hypervisor */
0176     movl    $0x100, %eax
0177     xorl    %edx, %edx
0178     movl    $MSR_AMD64_SEV_ES_GHCB, %ecx
0179     wrmsr
0180     rep; vmmcall
0181 
0182     /* If request fails, go to hlt loop */
0183     hlt
0184     jmp .Lfail
0185 SYM_CODE_END(startup32_vc_handler)
0186 
0187     .code64
0188 
0189 #include "../../kernel/sev_verify_cbit.S"
0190 
0191     .data
0192 
0193 #ifdef CONFIG_AMD_MEM_ENCRYPT
0194     .balign 8
0195 SYM_DATA(sme_me_mask,       .quad 0)
0196 SYM_DATA(sev_status,        .quad 0)
0197 SYM_DATA(sev_check_data,    .quad 0)
0198 #endif