2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2017-12-04 10:57:28 -06:00
/*
2019-12-04 11:48:58 +05:30
* AMD Secure Encrypted Virtualization ( SEV ) interface
2017-12-04 10:57:28 -06:00
*
2019-12-04 11:48:58 +05:30
* Copyright ( C ) 2016 , 2019 Advanced Micro Devices , Inc .
2017-12-04 10:57:28 -06:00
*
* Author : Brijesh Singh < brijesh . singh @ amd . com >
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/kthread.h>
# include <linux/sched.h>
# include <linux/interrupt.h>
# include <linux/spinlock.h>
# include <linux/spinlock_types.h>
# include <linux/types.h>
# include <linux/mutex.h>
# include <linux/delay.h>
# include <linux/hw_random.h>
# include <linux/ccp.h>
2018-05-25 15:23:29 -05:00
# include <linux/firmware.h>
2020-04-21 12:44:49 -05:00
# include <linux/gfp.h>
2017-12-04 10:57:28 -06:00
2019-10-03 21:17:46 +00:00
# include <asm/smp.h>
2019-12-04 11:48:59 +05:30
# include "psp-dev.h"
2019-12-04 11:48:58 +05:30
# include "sev-dev.h"
2017-12-04 10:57:28 -06:00
2018-09-14 17:32:04 -05:00
# define DEVICE_NAME "sev"
# define SEV_FW_FILE "amd / sev.fw"
# define SEV_FW_NAME_SIZE 64
2017-12-04 10:57:28 -06:00
static DEFINE_MUTEX ( sev_cmd_mutex ) ;
static struct sev_misc_dev * misc_dev ;
2018-08-15 16:11:25 -05:00
static int psp_cmd_timeout = 100 ;
module_param ( psp_cmd_timeout , int , 0644 ) ;
MODULE_PARM_DESC ( psp_cmd_timeout , " default timeout value, in seconds, for PSP commands " ) ;
static int psp_probe_timeout = 5 ;
module_param ( psp_probe_timeout , int , 0644 ) ;
MODULE_PARM_DESC ( psp_probe_timeout , " default timeout value, in seconds, during PSP device probe " ) ;
static bool psp_dead ;
static int psp_timeout ;
2020-04-21 12:44:49 -05:00
/* Trusted Memory Region (TMR):
* The TMR is a 1 MB area that must be 1 MB aligned . Use the page allocator
* to allocate the memory , which will return aligned memory for the specified
* allocation order .
*/
# define SEV_ES_TMR_SIZE (1024 * 1024)
static void * sev_es_tmr ;
2019-07-12 13:41:58 -07:00
static inline bool sev_version_greater_or_equal ( u8 maj , u8 min )
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp_master - > sev_data ;
2017-12-04 10:57:28 -06:00
2019-12-04 11:48:59 +05:30
if ( sev - > api_major > maj )
return true ;
2017-12-04 10:57:28 -06:00
2019-12-04 11:48:59 +05:30
if ( sev - > api_major = = maj & & sev - > api_minor > = min )
return true ;
2017-12-04 10:57:28 -06:00
2019-12-04 11:48:59 +05:30
return false ;
2017-12-04 10:57:28 -06:00
}
2019-12-04 11:48:59 +05:30
static void sev_irq_handler ( int irq , void * data , unsigned int status )
2017-12-04 10:57:28 -06:00
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = data ;
2017-12-04 10:57:28 -06:00
int reg ;
/* Check if it is command completion: */
2019-12-04 11:48:59 +05:30
if ( ! ( status & SEV_CMD_COMPLETE ) )
return ;
2017-12-04 10:57:28 -06:00
/* Check if it is SEV command completion: */
2019-12-04 11:49:00 +05:30
reg = ioread32 ( sev - > io_regs + sev - > vdata - > cmdresp_reg ) ;
2017-12-04 10:57:28 -06:00
if ( reg & PSP_CMDRESP_RESP ) {
2019-12-04 11:48:59 +05:30
sev - > int_rcvd = 1 ;
wake_up ( & sev - > int_queue ) ;
2017-12-04 10:57:28 -06:00
}
2017-12-04 10:57:28 -06:00
}
2019-12-04 11:48:59 +05:30
static int sev_wait_cmd_ioc ( struct sev_device * sev ,
2018-08-15 16:11:25 -05:00
unsigned int * reg , unsigned int timeout )
2017-12-04 10:57:28 -06:00
{
2018-08-15 16:11:25 -05:00
int ret ;
2019-12-04 11:48:59 +05:30
ret = wait_event_timeout ( sev - > int_queue ,
sev - > int_rcvd , timeout * HZ ) ;
2018-08-15 16:11:25 -05:00
if ( ! ret )
return - ETIMEDOUT ;
2019-12-04 11:49:00 +05:30
* reg = ioread32 ( sev - > io_regs + sev - > vdata - > cmdresp_reg ) ;
2018-08-15 16:11:25 -05:00
return 0 ;
2017-12-04 10:57:28 -06:00
}
static int sev_cmd_buffer_len ( int cmd )
{
switch ( cmd ) {
case SEV_CMD_INIT : return sizeof ( struct sev_data_init ) ;
case SEV_CMD_PLATFORM_STATUS : return sizeof ( struct sev_user_data_status ) ;
case SEV_CMD_PEK_CSR : return sizeof ( struct sev_data_pek_csr ) ;
case SEV_CMD_PEK_CERT_IMPORT : return sizeof ( struct sev_data_pek_cert_import ) ;
case SEV_CMD_PDH_CERT_EXPORT : return sizeof ( struct sev_data_pdh_cert_export ) ;
case SEV_CMD_LAUNCH_START : return sizeof ( struct sev_data_launch_start ) ;
case SEV_CMD_LAUNCH_UPDATE_DATA : return sizeof ( struct sev_data_launch_update_data ) ;
case SEV_CMD_LAUNCH_UPDATE_VMSA : return sizeof ( struct sev_data_launch_update_vmsa ) ;
case SEV_CMD_LAUNCH_FINISH : return sizeof ( struct sev_data_launch_finish ) ;
case SEV_CMD_LAUNCH_MEASURE : return sizeof ( struct sev_data_launch_measure ) ;
case SEV_CMD_ACTIVATE : return sizeof ( struct sev_data_activate ) ;
case SEV_CMD_DEACTIVATE : return sizeof ( struct sev_data_deactivate ) ;
case SEV_CMD_DECOMMISSION : return sizeof ( struct sev_data_decommission ) ;
case SEV_CMD_GUEST_STATUS : return sizeof ( struct sev_data_guest_status ) ;
case SEV_CMD_DBG_DECRYPT : return sizeof ( struct sev_data_dbg ) ;
case SEV_CMD_DBG_ENCRYPT : return sizeof ( struct sev_data_dbg ) ;
case SEV_CMD_SEND_START : return sizeof ( struct sev_data_send_start ) ;
case SEV_CMD_SEND_UPDATE_DATA : return sizeof ( struct sev_data_send_update_data ) ;
case SEV_CMD_SEND_UPDATE_VMSA : return sizeof ( struct sev_data_send_update_vmsa ) ;
case SEV_CMD_SEND_FINISH : return sizeof ( struct sev_data_send_finish ) ;
case SEV_CMD_RECEIVE_START : return sizeof ( struct sev_data_receive_start ) ;
case SEV_CMD_RECEIVE_FINISH : return sizeof ( struct sev_data_receive_finish ) ;
case SEV_CMD_RECEIVE_UPDATE_DATA : return sizeof ( struct sev_data_receive_update_data ) ;
case SEV_CMD_RECEIVE_UPDATE_VMSA : return sizeof ( struct sev_data_receive_update_vmsa ) ;
case SEV_CMD_LAUNCH_UPDATE_SECRET : return sizeof ( struct sev_data_launch_secret ) ;
2018-05-25 15:23:29 -05:00
case SEV_CMD_DOWNLOAD_FIRMWARE : return sizeof ( struct sev_data_download_firmware ) ;
2018-05-25 15:23:30 -05:00
case SEV_CMD_GET_ID : return sizeof ( struct sev_data_get_id ) ;
2017-12-04 10:57:28 -06:00
default : return 0 ;
}
return 0 ;
}
static int __sev_do_cmd_locked ( int cmd , void * data , int * psp_ret )
{
struct psp_device * psp = psp_master ;
2019-12-04 11:48:59 +05:30
struct sev_device * sev ;
2017-12-04 10:57:28 -06:00
unsigned int phys_lsb , phys_msb ;
unsigned int reg , ret = 0 ;
2019-12-04 11:48:59 +05:30
if ( ! psp | | ! psp - > sev_data )
2017-12-04 10:57:28 -06:00
return - ENODEV ;
2018-08-15 16:11:25 -05:00
if ( psp_dead )
return - EBUSY ;
2019-12-04 11:48:59 +05:30
sev = psp - > sev_data ;
2017-12-04 10:57:28 -06:00
/* Get the physical address of the command buffer */
phys_lsb = data ? lower_32_bits ( __psp_pa ( data ) ) : 0 ;
phys_msb = data ? upper_32_bits ( __psp_pa ( data ) ) : 0 ;
2019-12-04 11:48:59 +05:30
dev_dbg ( sev - > dev , " sev command id %#x buffer 0x%08x%08x timeout %us \n " ,
2018-08-15 16:11:25 -05:00
cmd , phys_msb , phys_lsb , psp_timeout ) ;
2017-12-04 10:57:28 -06:00
print_hex_dump_debug ( " (in): " , DUMP_PREFIX_OFFSET , 16 , 2 , data ,
sev_cmd_buffer_len ( cmd ) , false ) ;
2019-12-04 11:49:00 +05:30
iowrite32 ( phys_lsb , sev - > io_regs + sev - > vdata - > cmdbuff_addr_lo_reg ) ;
iowrite32 ( phys_msb , sev - > io_regs + sev - > vdata - > cmdbuff_addr_hi_reg ) ;
2017-12-04 10:57:28 -06:00
2019-12-04 11:48:59 +05:30
sev - > int_rcvd = 0 ;
2018-07-03 12:11:33 -05:00
2017-12-04 10:57:28 -06:00
reg = cmd ;
2019-12-04 11:48:59 +05:30
reg < < = SEV_CMDRESP_CMD_SHIFT ;
reg | = SEV_CMDRESP_IOC ;
2019-12-04 11:49:00 +05:30
iowrite32 ( reg , sev - > io_regs + sev - > vdata - > cmdresp_reg ) ;
2017-12-04 10:57:28 -06:00
/* wait for command completion */
2019-12-04 11:48:59 +05:30
ret = sev_wait_cmd_ioc ( sev , & reg , psp_timeout ) ;
2018-08-15 16:11:25 -05:00
if ( ret ) {
if ( psp_ret )
* psp_ret = 0 ;
2019-12-04 11:48:59 +05:30
dev_err ( sev - > dev , " sev command %#x timed out, disabling PSP \n " , cmd ) ;
2018-08-15 16:11:25 -05:00
psp_dead = true ;
return ret ;
}
psp_timeout = psp_cmd_timeout ;
2017-12-04 10:57:28 -06:00
if ( psp_ret )
* psp_ret = reg & PSP_CMDRESP_ERR_MASK ;
if ( reg & PSP_CMDRESP_ERR_MASK ) {
2019-12-04 11:48:59 +05:30
dev_dbg ( sev - > dev , " sev command %#x failed (%#010x) \n " ,
2017-12-04 10:57:28 -06:00
cmd , reg & PSP_CMDRESP_ERR_MASK ) ;
ret = - EIO ;
}
print_hex_dump_debug ( " (out): " , DUMP_PREFIX_OFFSET , 16 , 2 , data ,
sev_cmd_buffer_len ( cmd ) , false ) ;
return ret ;
}
static int sev_do_cmd ( int cmd , void * data , int * psp_ret )
{
int rc ;
mutex_lock ( & sev_cmd_mutex ) ;
rc = __sev_do_cmd_locked ( cmd , data , psp_ret ) ;
mutex_unlock ( & sev_cmd_mutex ) ;
return rc ;
}
static int __sev_platform_init_locked ( int * error )
{
struct psp_device * psp = psp_master ;
2019-12-04 11:48:59 +05:30
struct sev_device * sev ;
2017-12-04 10:57:28 -06:00
int rc = 0 ;
2019-12-04 11:48:59 +05:30
if ( ! psp | | ! psp - > sev_data )
2017-12-04 10:57:28 -06:00
return - ENODEV ;
2019-12-04 11:48:59 +05:30
sev = psp - > sev_data ;
if ( sev - > state = = SEV_STATE_INIT )
2017-12-04 10:57:28 -06:00
return 0 ;
2020-04-21 12:44:49 -05:00
if ( sev_es_tmr ) {
u64 tmr_pa ;
/*
* Do not include the encryption mask on the physical
* address of the TMR ( firmware should clear it anyway ) .
*/
tmr_pa = __pa ( sev_es_tmr ) ;
sev - > init_cmd_buf . flags | = SEV_INIT_FLAGS_SEV_ES ;
sev - > init_cmd_buf . tmr_address = tmr_pa ;
sev - > init_cmd_buf . tmr_len = SEV_ES_TMR_SIZE ;
}
2019-12-04 11:48:59 +05:30
rc = __sev_do_cmd_locked ( SEV_CMD_INIT , & sev - > init_cmd_buf , error ) ;
2017-12-04 10:57:28 -06:00
if ( rc )
return rc ;
2019-12-04 11:48:59 +05:30
sev - > state = SEV_STATE_INIT ;
2019-10-03 21:17:46 +00:00
/* Prepare for first SEV guest launch after INIT */
wbinvd_on_all_cpus ( ) ;
rc = __sev_do_cmd_locked ( SEV_CMD_DF_FLUSH , NULL , error ) ;
if ( rc )
return rc ;
2019-12-04 11:48:59 +05:30
dev_dbg ( sev - > dev , " SEV firmware initialized \n " ) ;
2017-12-04 10:57:28 -06:00
return rc ;
}
int sev_platform_init ( int * error )
{
int rc ;
mutex_lock ( & sev_cmd_mutex ) ;
rc = __sev_platform_init_locked ( error ) ;
mutex_unlock ( & sev_cmd_mutex ) ;
return rc ;
}
EXPORT_SYMBOL_GPL ( sev_platform_init ) ;
static int __sev_platform_shutdown_locked ( int * error )
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp_master - > sev_data ;
2017-12-04 10:57:28 -06:00
int ret ;
2018-02-15 13:34:44 -06:00
ret = __sev_do_cmd_locked ( SEV_CMD_SHUTDOWN , NULL , error ) ;
2017-12-04 10:57:28 -06:00
if ( ret )
return ret ;
2019-12-04 11:48:59 +05:30
sev - > state = SEV_STATE_UNINIT ;
dev_dbg ( sev - > dev , " SEV firmware shutdown \n " ) ;
2017-12-04 10:57:28 -06:00
return ret ;
}
static int sev_platform_shutdown ( int * error )
{
int rc ;
mutex_lock ( & sev_cmd_mutex ) ;
rc = __sev_platform_shutdown_locked ( NULL ) ;
mutex_unlock ( & sev_cmd_mutex ) ;
return rc ;
}
2017-12-04 10:57:29 -06:00
static int sev_get_platform_state ( int * state , int * error )
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp_master - > sev_data ;
2017-12-04 10:57:29 -06:00
int rc ;
rc = __sev_do_cmd_locked ( SEV_CMD_PLATFORM_STATUS ,
2019-12-04 11:48:59 +05:30
& sev - > status_cmd_buf , error ) ;
2017-12-04 10:57:29 -06:00
if ( rc )
return rc ;
2019-12-04 11:48:59 +05:30
* state = sev - > status_cmd_buf . state ;
2017-12-04 10:57:29 -06:00
return rc ;
}
2020-03-06 09:20:10 -08:00
static int sev_ioctl_do_reset ( struct sev_issue_cmd * argp , bool writable )
2017-12-04 10:57:29 -06:00
{
int state , rc ;
2020-03-06 09:20:10 -08:00
if ( ! writable )
2019-11-12 13:58:34 -06:00
return - EPERM ;
2017-12-04 10:57:29 -06:00
/*
* The SEV spec requires that FACTORY_RESET must be issued in
* UNINIT state . Before we go further lets check if any guest is
* active .
*
* If FW is in WORKING state then deny the request otherwise issue
* SHUTDOWN command do INIT - > UNINIT before issuing the FACTORY_RESET .
*
*/
rc = sev_get_platform_state ( & state , & argp - > error ) ;
if ( rc )
return rc ;
if ( state = = SEV_STATE_WORKING )
return - EBUSY ;
if ( state = = SEV_STATE_INIT ) {
rc = __sev_platform_shutdown_locked ( & argp - > error ) ;
if ( rc )
return rc ;
}
2018-02-15 13:34:44 -06:00
return __sev_do_cmd_locked ( SEV_CMD_FACTORY_RESET , NULL , & argp - > error ) ;
2017-12-04 10:57:29 -06:00
}
2017-12-04 10:57:29 -06:00
static int sev_ioctl_do_platform_status ( struct sev_issue_cmd * argp )
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp_master - > sev_data ;
struct sev_user_data_status * data = & sev - > status_cmd_buf ;
2017-12-04 10:57:29 -06:00
int ret ;
ret = __sev_do_cmd_locked ( SEV_CMD_PLATFORM_STATUS , data , & argp - > error ) ;
if ( ret )
return ret ;
if ( copy_to_user ( ( void __user * ) argp - > data , data , sizeof ( * data ) ) )
ret = - EFAULT ;
return ret ;
}
2020-03-06 09:20:10 -08:00
static int sev_ioctl_do_pek_pdh_gen ( int cmd , struct sev_issue_cmd * argp , bool writable )
2017-12-04 10:57:30 -06:00
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp_master - > sev_data ;
2017-12-04 10:57:30 -06:00
int rc ;
2020-03-06 09:20:10 -08:00
if ( ! writable )
2019-11-12 13:58:34 -06:00
return - EPERM ;
2019-12-04 11:48:59 +05:30
if ( sev - > state = = SEV_STATE_UNINIT ) {
2017-12-04 10:57:30 -06:00
rc = __sev_platform_init_locked ( & argp - > error ) ;
if ( rc )
return rc ;
}
2018-02-15 13:34:44 -06:00
return __sev_do_cmd_locked ( cmd , NULL , & argp - > error ) ;
2017-12-04 10:57:30 -06:00
}
2020-03-06 09:20:10 -08:00
static int sev_ioctl_do_pek_csr ( struct sev_issue_cmd * argp , bool writable )
2017-12-04 10:57:31 -06:00
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp_master - > sev_data ;
2017-12-04 10:57:31 -06:00
struct sev_user_data_pek_csr input ;
struct sev_data_pek_csr * data ;
2020-06-04 18:09:41 +10:00
void __user * input_address ;
2017-12-04 10:57:31 -06:00
void * blob = NULL ;
int ret ;
2020-03-06 09:20:10 -08:00
if ( ! writable )
2019-11-12 13:58:34 -06:00
return - EPERM ;
2017-12-04 10:57:31 -06:00
if ( copy_from_user ( & input , ( void __user * ) argp - > data , sizeof ( input ) ) )
return - EFAULT ;
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
/* userspace wants to query CSR length */
if ( ! input . address | | ! input . length )
goto cmd ;
/* allocate a physically contiguous buffer to store the CSR blob */
2020-06-04 18:09:41 +10:00
input_address = ( void __user * ) input . address ;
2020-04-22 22:56:59 -04:00
if ( input . length > SEV_FW_BLOB_MAX_SIZE ) {
2017-12-04 10:57:31 -06:00
ret = - EFAULT ;
goto e_free ;
}
blob = kmalloc ( input . length , GFP_KERNEL ) ;
if ( ! blob ) {
ret = - ENOMEM ;
goto e_free ;
}
data - > address = __psp_pa ( blob ) ;
data - > len = input . length ;
cmd :
2019-12-04 11:48:59 +05:30
if ( sev - > state = = SEV_STATE_UNINIT ) {
2017-12-04 10:57:31 -06:00
ret = __sev_platform_init_locked ( & argp - > error ) ;
if ( ret )
goto e_free_blob ;
}
ret = __sev_do_cmd_locked ( SEV_CMD_PEK_CSR , data , & argp - > error ) ;
/* If we query the CSR length, FW responded with expected data. */
input . length = data - > len ;
if ( copy_to_user ( ( void __user * ) argp - > data , & input , sizeof ( input ) ) ) {
ret = - EFAULT ;
goto e_free_blob ;
}
if ( blob ) {
2020-06-04 18:09:41 +10:00
if ( copy_to_user ( input_address , blob , input . length ) )
2017-12-04 10:57:31 -06:00
ret = - EFAULT ;
}
e_free_blob :
kfree ( blob ) ;
e_free :
kfree ( data ) ;
return ret ;
}
2020-06-04 18:09:41 +10:00
void * psp_copy_user_blob ( u64 uaddr , u32 len )
2017-12-04 10:57:31 -06:00
{
if ( ! uaddr | | ! len )
return ERR_PTR ( - EINVAL ) ;
/* verify that blob length does not exceed our limit */
if ( len > SEV_FW_BLOB_MAX_SIZE )
return ERR_PTR ( - EINVAL ) ;
2020-06-04 18:09:41 +10:00
return memdup_user ( ( void __user * ) uaddr , len ) ;
2017-12-04 10:57:31 -06:00
}
EXPORT_SYMBOL_GPL ( psp_copy_user_blob ) ;
2018-05-25 15:23:29 -05:00
static int sev_get_api_version ( void )
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp_master - > sev_data ;
2018-05-25 15:23:29 -05:00
struct sev_user_data_status * status ;
2018-09-14 17:32:03 -05:00
int error = 0 , ret ;
2018-05-25 15:23:29 -05:00
2019-12-04 11:48:59 +05:30
status = & sev - > status_cmd_buf ;
2018-05-25 15:23:29 -05:00
ret = sev_platform_status ( status , & error ) ;
if ( ret ) {
2019-12-04 11:48:59 +05:30
dev_err ( sev - > dev ,
2018-05-25 15:23:29 -05:00
" SEV: failed to get status. Error: %#x \n " , error ) ;
return 1 ;
}
2019-12-04 11:48:59 +05:30
sev - > api_major = status - > api_major ;
sev - > api_minor = status - > api_minor ;
sev - > build = status - > build ;
sev - > state = status - > state ;
2018-05-25 15:23:29 -05:00
return 0 ;
}
2018-09-26 02:09:23 +00:00
static int sev_get_firmware ( struct device * dev ,
const struct firmware * * firmware )
2018-09-14 17:32:04 -05:00
{
char fw_name_specific [ SEV_FW_NAME_SIZE ] ;
char fw_name_subset [ SEV_FW_NAME_SIZE ] ;
snprintf ( fw_name_specific , sizeof ( fw_name_specific ) ,
" amd/amd_sev_fam%.2xh_model%.2xh.sbin " ,
boot_cpu_data . x86 , boot_cpu_data . x86_model ) ;
snprintf ( fw_name_subset , sizeof ( fw_name_subset ) ,
" amd/amd_sev_fam%.2xh_model%.1xxh.sbin " ,
boot_cpu_data . x86 , ( boot_cpu_data . x86_model & 0xf0 ) > > 4 ) ;
/* Check for SEV FW for a particular model.
* Ex . amd_sev_fam17h_model00h . sbin for Family 17 h Model 00 h
*
* or
*
* Check for SEV FW common to a subset of models .
* Ex . amd_sev_fam17h_model0xh . sbin for
* Family 17 h Model 00 h - - Family 17 h Model 0F h
*
* or
*
* Fall - back to using generic name : sev . fw
*/
if ( ( firmware_request_nowarn ( firmware , fw_name_specific , dev ) > = 0 ) | |
( firmware_request_nowarn ( firmware , fw_name_subset , dev ) > = 0 ) | |
( firmware_request_nowarn ( firmware , SEV_FW_FILE , dev ) > = 0 ) )
return 0 ;
return - ENOENT ;
}
2018-05-25 15:23:29 -05:00
/* Don't fail if SEV FW couldn't be updated. Continue with existing SEV FW */
static int sev_update_firmware ( struct device * dev )
{
struct sev_data_download_firmware * data ;
const struct firmware * firmware ;
int ret , error , order ;
struct page * p ;
u64 data_size ;
2018-09-14 17:32:04 -05:00
if ( sev_get_firmware ( dev , & firmware ) = = - ENOENT ) {
dev_dbg ( dev , " No SEV firmware file present \n " ) ;
2018-05-25 15:23:29 -05:00
return - 1 ;
2018-09-14 17:32:04 -05:00
}
2018-05-25 15:23:29 -05:00
/*
* SEV FW expects the physical address given to it to be 32
* byte aligned . Memory allocated has structure placed at the
* beginning followed by the firmware being passed to the SEV
* FW . Allocate enough memory for data structure + alignment
* padding + SEV FW .
*/
data_size = ALIGN ( sizeof ( struct sev_data_download_firmware ) , 32 ) ;
order = get_order ( firmware - > size + data_size ) ;
p = alloc_pages ( GFP_KERNEL , order ) ;
if ( ! p ) {
ret = - 1 ;
goto fw_err ;
}
/*
* Copy firmware data to a kernel allocated contiguous
* memory region .
*/
data = page_address ( p ) ;
memcpy ( page_address ( p ) + data_size , firmware - > data , firmware - > size ) ;
data - > address = __psp_pa ( page_address ( p ) + data_size ) ;
data - > len = firmware - > size ;
ret = sev_do_cmd ( SEV_CMD_DOWNLOAD_FIRMWARE , data , & error ) ;
if ( ret )
dev_dbg ( dev , " Failed to update SEV firmware: %#x \n " , error ) ;
else
dev_info ( dev , " SEV firmware update successful \n " ) ;
__free_pages ( p , order ) ;
fw_err :
release_firmware ( firmware ) ;
return ret ;
}
2020-03-06 09:20:10 -08:00
static int sev_ioctl_do_pek_import ( struct sev_issue_cmd * argp , bool writable )
2017-12-04 10:57:31 -06:00
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp_master - > sev_data ;
2017-12-04 10:57:31 -06:00
struct sev_user_data_pek_cert_import input ;
struct sev_data_pek_cert_import * data ;
void * pek_blob , * oca_blob ;
int ret ;
2020-03-06 09:20:10 -08:00
if ( ! writable )
2019-11-12 13:58:34 -06:00
return - EPERM ;
2017-12-04 10:57:31 -06:00
if ( copy_from_user ( & input , ( void __user * ) argp - > data , sizeof ( input ) ) )
return - EFAULT ;
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
/* copy PEK certificate blobs from userspace */
pek_blob = psp_copy_user_blob ( input . pek_cert_address , input . pek_cert_len ) ;
if ( IS_ERR ( pek_blob ) ) {
ret = PTR_ERR ( pek_blob ) ;
goto e_free ;
}
data - > pek_cert_address = __psp_pa ( pek_blob ) ;
data - > pek_cert_len = input . pek_cert_len ;
/* copy PEK certificate blobs from userspace */
oca_blob = psp_copy_user_blob ( input . oca_cert_address , input . oca_cert_len ) ;
if ( IS_ERR ( oca_blob ) ) {
ret = PTR_ERR ( oca_blob ) ;
goto e_free_pek ;
}
data - > oca_cert_address = __psp_pa ( oca_blob ) ;
data - > oca_cert_len = input . oca_cert_len ;
/* If platform is not in INIT state then transition it to INIT */
2019-12-04 11:48:59 +05:30
if ( sev - > state ! = SEV_STATE_INIT ) {
2017-12-04 10:57:31 -06:00
ret = __sev_platform_init_locked ( & argp - > error ) ;
if ( ret )
goto e_free_oca ;
}
ret = __sev_do_cmd_locked ( SEV_CMD_PEK_CERT_IMPORT , data , & argp - > error ) ;
e_free_oca :
kfree ( oca_blob ) ;
e_free_pek :
kfree ( pek_blob ) ;
e_free :
kfree ( data ) ;
return ret ;
}
2019-03-28 21:58:52 +00:00
static int sev_ioctl_do_get_id2 ( struct sev_issue_cmd * argp )
{
struct sev_user_data_get_id2 input ;
struct sev_data_get_id * data ;
2020-06-04 18:09:41 +10:00
void __user * input_address ;
2019-03-28 21:58:52 +00:00
void * id_blob = NULL ;
int ret ;
/* SEV GET_ID is available from SEV API v0.16 and up */
2019-07-12 13:41:58 -07:00
if ( ! sev_version_greater_or_equal ( 0 , 16 ) )
2019-03-28 21:58:52 +00:00
return - ENOTSUPP ;
if ( copy_from_user ( & input , ( void __user * ) argp - > data , sizeof ( input ) ) )
return - EFAULT ;
2020-06-04 18:09:41 +10:00
input_address = ( void __user * ) input . address ;
2019-03-28 21:58:52 +00:00
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
if ( input . address & & input . length ) {
id_blob = kmalloc ( input . length , GFP_KERNEL ) ;
if ( ! id_blob ) {
kfree ( data ) ;
return - ENOMEM ;
}
data - > address = __psp_pa ( id_blob ) ;
data - > len = input . length ;
}
ret = __sev_do_cmd_locked ( SEV_CMD_GET_ID , data , & argp - > error ) ;
/*
* Firmware will return the length of the ID value ( either the minimum
* required length or the actual length written ) , return it to the user .
*/
input . length = data - > len ;
if ( copy_to_user ( ( void __user * ) argp - > data , & input , sizeof ( input ) ) ) {
ret = - EFAULT ;
goto e_free ;
}
if ( id_blob ) {
2020-06-04 18:09:41 +10:00
if ( copy_to_user ( input_address , id_blob , data - > len ) ) {
2019-03-28 21:58:52 +00:00
ret = - EFAULT ;
goto e_free ;
}
}
e_free :
kfree ( id_blob ) ;
kfree ( data ) ;
return ret ;
}
2018-05-25 15:23:30 -05:00
static int sev_ioctl_do_get_id ( struct sev_issue_cmd * argp )
{
struct sev_data_get_id * data ;
u64 data_size , user_size ;
void * id_blob , * mem ;
int ret ;
/* SEV GET_ID available from SEV API v0.16 and up */
2019-07-12 13:41:58 -07:00
if ( ! sev_version_greater_or_equal ( 0 , 16 ) )
2018-05-25 15:23:30 -05:00
return - ENOTSUPP ;
/* SEV FW expects the buffer it fills with the ID to be
* 8 - byte aligned . Memory allocated should be enough to
* hold data structure + alignment padding + memory
* where SEV FW writes the ID .
*/
data_size = ALIGN ( sizeof ( struct sev_data_get_id ) , 8 ) ;
user_size = sizeof ( struct sev_user_data_get_id ) ;
mem = kzalloc ( data_size + user_size , GFP_KERNEL ) ;
if ( ! mem )
return - ENOMEM ;
data = mem ;
id_blob = mem + data_size ;
data - > address = __psp_pa ( id_blob ) ;
data - > len = user_size ;
ret = __sev_do_cmd_locked ( SEV_CMD_GET_ID , data , & argp - > error ) ;
if ( ! ret ) {
if ( copy_to_user ( ( void __user * ) argp - > data , id_blob , data - > len ) )
ret = - EFAULT ;
}
kfree ( mem ) ;
return ret ;
}
2020-03-06 09:20:10 -08:00
static int sev_ioctl_do_pdh_export ( struct sev_issue_cmd * argp , bool writable )
2017-12-04 10:57:31 -06:00
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp_master - > sev_data ;
2017-12-04 10:57:31 -06:00
struct sev_user_data_pdh_cert_export input ;
void * pdh_blob = NULL , * cert_blob = NULL ;
struct sev_data_pdh_cert_export * data ;
2020-06-04 18:09:41 +10:00
void __user * input_cert_chain_address ;
void __user * input_pdh_cert_address ;
2017-12-04 10:57:31 -06:00
int ret ;
2019-11-12 13:58:34 -06:00
/* If platform is not in INIT state then transition it to INIT. */
2019-12-04 11:48:59 +05:30
if ( sev - > state ! = SEV_STATE_INIT ) {
2020-03-06 09:20:10 -08:00
if ( ! writable )
2019-11-12 13:58:34 -06:00
return - EPERM ;
ret = __sev_platform_init_locked ( & argp - > error ) ;
if ( ret )
return ret ;
}
2017-12-04 10:57:31 -06:00
if ( copy_from_user ( & input , ( void __user * ) argp - > data , sizeof ( input ) ) )
return - EFAULT ;
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
/* Userspace wants to query the certificate length. */
if ( ! input . pdh_cert_address | |
! input . pdh_cert_len | |
! input . cert_chain_address )
goto cmd ;
2020-06-04 18:09:41 +10:00
input_pdh_cert_address = ( void __user * ) input . pdh_cert_address ;
input_cert_chain_address = ( void __user * ) input . cert_chain_address ;
2017-12-04 10:57:31 -06:00
/* Allocate a physically contiguous buffer to store the PDH blob. */
2020-04-22 22:56:59 -04:00
if ( input . pdh_cert_len > SEV_FW_BLOB_MAX_SIZE ) {
2017-12-04 10:57:31 -06:00
ret = - EFAULT ;
goto e_free ;
}
/* Allocate a physically contiguous buffer to store the cert chain blob. */
2020-04-22 22:56:59 -04:00
if ( input . cert_chain_len > SEV_FW_BLOB_MAX_SIZE ) {
2017-12-04 10:57:31 -06:00
ret = - EFAULT ;
goto e_free ;
}
pdh_blob = kmalloc ( input . pdh_cert_len , GFP_KERNEL ) ;
if ( ! pdh_blob ) {
ret = - ENOMEM ;
goto e_free ;
}
data - > pdh_cert_address = __psp_pa ( pdh_blob ) ;
data - > pdh_cert_len = input . pdh_cert_len ;
cert_blob = kmalloc ( input . cert_chain_len , GFP_KERNEL ) ;
if ( ! cert_blob ) {
ret = - ENOMEM ;
goto e_free_pdh ;
}
data - > cert_chain_address = __psp_pa ( cert_blob ) ;
data - > cert_chain_len = input . cert_chain_len ;
cmd :
ret = __sev_do_cmd_locked ( SEV_CMD_PDH_CERT_EXPORT , data , & argp - > error ) ;
/* If we query the length, FW responded with expected data. */
input . cert_chain_len = data - > cert_chain_len ;
input . pdh_cert_len = data - > pdh_cert_len ;
if ( copy_to_user ( ( void __user * ) argp - > data , & input , sizeof ( input ) ) ) {
ret = - EFAULT ;
goto e_free_cert ;
}
if ( pdh_blob ) {
2020-06-04 18:09:41 +10:00
if ( copy_to_user ( input_pdh_cert_address ,
2017-12-04 10:57:31 -06:00
pdh_blob , input . pdh_cert_len ) ) {
ret = - EFAULT ;
goto e_free_cert ;
}
}
if ( cert_blob ) {
2020-06-04 18:09:41 +10:00
if ( copy_to_user ( input_cert_chain_address ,
2017-12-04 10:57:31 -06:00
cert_blob , input . cert_chain_len ) )
ret = - EFAULT ;
}
e_free_cert :
kfree ( cert_blob ) ;
e_free_pdh :
kfree ( pdh_blob ) ;
e_free :
kfree ( data ) ;
return ret ;
}
2017-12-04 10:57:28 -06:00
static long sev_ioctl ( struct file * file , unsigned int ioctl , unsigned long arg )
{
2017-12-04 10:57:29 -06:00
void __user * argp = ( void __user * ) arg ;
struct sev_issue_cmd input ;
int ret = - EFAULT ;
2020-03-06 09:20:10 -08:00
bool writable = file - > f_mode & FMODE_WRITE ;
2017-12-04 10:57:29 -06:00
2019-12-04 11:48:59 +05:30
if ( ! psp_master | | ! psp_master - > sev_data )
2017-12-04 10:57:29 -06:00
return - ENODEV ;
if ( ioctl ! = SEV_ISSUE_CMD )
return - EINVAL ;
if ( copy_from_user ( & input , argp , sizeof ( struct sev_issue_cmd ) ) )
return - EFAULT ;
if ( input . cmd > SEV_MAX )
return - EINVAL ;
mutex_lock ( & sev_cmd_mutex ) ;
switch ( input . cmd ) {
case SEV_FACTORY_RESET :
2020-03-06 09:20:10 -08:00
ret = sev_ioctl_do_reset ( & input , writable ) ;
2017-12-04 10:57:29 -06:00
break ;
2017-12-04 10:57:29 -06:00
case SEV_PLATFORM_STATUS :
ret = sev_ioctl_do_platform_status ( & input ) ;
break ;
2017-12-04 10:57:30 -06:00
case SEV_PEK_GEN :
2020-03-06 09:20:10 -08:00
ret = sev_ioctl_do_pek_pdh_gen ( SEV_CMD_PEK_GEN , & input , writable ) ;
2017-12-04 10:57:30 -06:00
break ;
2017-12-04 10:57:30 -06:00
case SEV_PDH_GEN :
2020-03-06 09:20:10 -08:00
ret = sev_ioctl_do_pek_pdh_gen ( SEV_CMD_PDH_GEN , & input , writable ) ;
2017-12-04 10:57:30 -06:00
break ;
2017-12-04 10:57:31 -06:00
case SEV_PEK_CSR :
2020-03-06 09:20:10 -08:00
ret = sev_ioctl_do_pek_csr ( & input , writable ) ;
2017-12-04 10:57:31 -06:00
break ;
2017-12-04 10:57:31 -06:00
case SEV_PEK_CERT_IMPORT :
2020-03-06 09:20:10 -08:00
ret = sev_ioctl_do_pek_import ( & input , writable ) ;
2017-12-04 10:57:31 -06:00
break ;
2017-12-04 10:57:31 -06:00
case SEV_PDH_CERT_EXPORT :
2020-03-06 09:20:10 -08:00
ret = sev_ioctl_do_pdh_export ( & input , writable ) ;
2017-12-04 10:57:31 -06:00
break ;
2018-05-25 15:23:30 -05:00
case SEV_GET_ID :
2019-03-28 21:58:52 +00:00
pr_warn_once ( " SEV_GET_ID command is deprecated, use SEV_GET_ID2 \n " ) ;
2018-05-25 15:23:30 -05:00
ret = sev_ioctl_do_get_id ( & input ) ;
break ;
2019-03-28 21:58:52 +00:00
case SEV_GET_ID2 :
ret = sev_ioctl_do_get_id2 ( & input ) ;
break ;
2017-12-04 10:57:29 -06:00
default :
ret = - EINVAL ;
goto out ;
}
if ( copy_to_user ( argp , & input , sizeof ( struct sev_issue_cmd ) ) )
ret = - EFAULT ;
out :
mutex_unlock ( & sev_cmd_mutex ) ;
return ret ;
2017-12-04 10:57:28 -06:00
}
static const struct file_operations sev_fops = {
. owner = THIS_MODULE ,
. unlocked_ioctl = sev_ioctl ,
} ;
int sev_platform_status ( struct sev_user_data_status * data , int * error )
{
return sev_do_cmd ( SEV_CMD_PLATFORM_STATUS , data , error ) ;
}
EXPORT_SYMBOL_GPL ( sev_platform_status ) ;
int sev_guest_deactivate ( struct sev_data_deactivate * data , int * error )
{
return sev_do_cmd ( SEV_CMD_DEACTIVATE , data , error ) ;
}
EXPORT_SYMBOL_GPL ( sev_guest_deactivate ) ;
int sev_guest_activate ( struct sev_data_activate * data , int * error )
{
return sev_do_cmd ( SEV_CMD_ACTIVATE , data , error ) ;
}
EXPORT_SYMBOL_GPL ( sev_guest_activate ) ;
int sev_guest_decommission ( struct sev_data_decommission * data , int * error )
{
return sev_do_cmd ( SEV_CMD_DECOMMISSION , data , error ) ;
}
EXPORT_SYMBOL_GPL ( sev_guest_decommission ) ;
int sev_guest_df_flush ( int * error )
{
2018-02-15 13:34:44 -06:00
return sev_do_cmd ( SEV_CMD_DF_FLUSH , NULL , error ) ;
2017-12-04 10:57:28 -06:00
}
EXPORT_SYMBOL_GPL ( sev_guest_df_flush ) ;
static void sev_exit ( struct kref * ref )
{
misc_deregister ( & misc_dev - > misc ) ;
2020-03-03 07:57:23 -06:00
kfree ( misc_dev ) ;
misc_dev = NULL ;
2017-12-04 10:57:28 -06:00
}
2019-12-04 11:48:59 +05:30
static int sev_misc_init ( struct sev_device * sev )
2017-12-04 10:57:28 -06:00
{
2019-12-04 11:48:59 +05:30
struct device * dev = sev - > dev ;
2017-12-04 10:57:28 -06:00
int ret ;
/*
* SEV feature support can be detected on multiple devices but the SEV
* FW commands must be issued on the master . During probe , we do not
* know the master hence we create / dev / sev on the first device probe .
* sev_do_cmd ( ) finds the right master device to which to issue the
* command to the firmware .
*/
if ( ! misc_dev ) {
struct miscdevice * misc ;
2020-03-03 07:57:23 -06:00
misc_dev = kzalloc ( sizeof ( * misc_dev ) , GFP_KERNEL ) ;
2017-12-04 10:57:28 -06:00
if ( ! misc_dev )
return - ENOMEM ;
misc = & misc_dev - > misc ;
misc - > minor = MISC_DYNAMIC_MINOR ;
misc - > name = DEVICE_NAME ;
misc - > fops = & sev_fops ;
ret = misc_register ( misc ) ;
if ( ret )
return ret ;
kref_init ( & misc_dev - > refcount ) ;
} else {
kref_get ( & misc_dev - > refcount ) ;
}
2019-12-04 11:48:59 +05:30
init_waitqueue_head ( & sev - > int_queue ) ;
sev - > misc = misc_dev ;
2017-12-04 10:57:28 -06:00
dev_dbg ( dev , " registered SEV device \n " ) ;
return 0 ;
}
2019-12-04 11:48:59 +05:30
int sev_dev_init ( struct psp_device * psp )
2017-12-04 10:57:28 -06:00
{
2019-12-04 11:48:59 +05:30
struct device * dev = psp - > dev ;
struct sev_device * sev ;
int ret = - ENOMEM ;
2017-12-04 10:57:28 -06:00
2019-12-04 11:48:59 +05:30
sev = devm_kzalloc ( dev , sizeof ( * sev ) , GFP_KERNEL ) ;
if ( ! sev )
2017-12-04 10:57:28 -06:00
goto e_err ;
2019-12-04 11:48:59 +05:30
psp - > sev_data = sev ;
2017-12-04 10:57:28 -06:00
2019-12-04 11:48:59 +05:30
sev - > dev = dev ;
sev - > psp = psp ;
2017-12-04 10:57:28 -06:00
2019-12-04 11:48:59 +05:30
sev - > io_regs = psp - > io_regs ;
2017-12-04 10:57:28 -06:00
2019-12-04 11:49:00 +05:30
sev - > vdata = ( struct sev_vdata * ) psp - > vdata - > sev ;
if ( ! sev - > vdata ) {
ret = - ENODEV ;
dev_err ( dev , " sev: missing driver data \n " ) ;
goto e_err ;
}
2019-12-04 11:48:59 +05:30
psp_set_sev_irq_handler ( psp , sev_irq_handler , sev ) ;
2019-02-15 17:26:33 +00:00
2019-12-04 11:48:59 +05:30
ret = sev_misc_init ( sev ) ;
2017-12-04 10:57:28 -06:00
if ( ret )
goto e_irq ;
2019-12-04 11:48:59 +05:30
dev_notice ( dev , " sev enabled \n " ) ;
2018-07-03 12:11:42 -05:00
2017-12-04 10:57:28 -06:00
return 0 ;
2017-12-04 10:57:28 -06:00
e_irq :
2019-12-04 11:48:59 +05:30
psp_clear_sev_irq_handler ( psp ) ;
2017-12-04 10:57:28 -06:00
e_err :
2019-12-04 11:48:59 +05:30
psp - > sev_data = NULL ;
2017-12-04 10:57:28 -06:00
2019-12-04 11:48:59 +05:30
dev_notice ( dev , " sev initialization failed \n " ) ;
2019-02-15 17:26:33 +00:00
2017-12-04 10:57:28 -06:00
return ret ;
}
2019-12-04 11:48:59 +05:30
void sev_dev_destroy ( struct psp_device * psp )
2017-12-04 10:57:28 -06:00
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp - > sev_data ;
2017-12-04 10:57:28 -06:00
2019-12-04 11:48:59 +05:30
if ( ! sev )
2018-07-26 09:37:59 -05:00
return ;
2019-12-04 11:48:59 +05:30
if ( sev - > misc )
2017-12-04 10:57:28 -06:00
kref_put ( & misc_dev - > refcount , sev_exit ) ;
2019-12-04 11:48:59 +05:30
psp_clear_sev_irq_handler ( psp ) ;
2017-12-04 10:57:28 -06:00
}
2017-12-04 10:57:28 -06:00
int sev_issue_cmd_external_user ( struct file * filep , unsigned int cmd ,
void * data , int * error )
{
if ( ! filep | | filep - > f_op ! = & sev_fops )
return - EBADF ;
2019-12-04 11:48:59 +05:30
return sev_do_cmd ( cmd , data , error ) ;
2017-12-04 10:57:28 -06:00
}
EXPORT_SYMBOL_GPL ( sev_issue_cmd_external_user ) ;
2019-12-04 11:48:59 +05:30
void sev_pci_init ( void )
2017-12-04 10:57:28 -06:00
{
2019-12-04 11:48:59 +05:30
struct sev_device * sev = psp_master - > sev_data ;
2020-04-21 12:44:49 -05:00
struct page * tmr_page ;
2017-12-04 10:57:28 -06:00
int error , rc ;
2019-12-04 11:48:59 +05:30
if ( ! sev )
2017-12-04 10:57:28 -06:00
return ;
2018-08-15 16:11:25 -05:00
psp_timeout = psp_probe_timeout ;
2018-05-25 15:23:29 -05:00
if ( sev_get_api_version ( ) )
goto err ;
2019-01-30 20:57:52 +00:00
/*
* If platform is not in UNINIT state then firmware upgrade and / or
* platform INIT command will fail . These command require UNINIT state .
*
* In a normal boot we should never run into case where the firmware
* is not in UNINIT state on boot . But in case of kexec boot , a reboot
* may not go through a typical shutdown sequence and may leave the
* firmware in INIT or WORKING state .
*/
2019-12-04 11:48:59 +05:30
if ( sev - > state ! = SEV_STATE_UNINIT ) {
2019-01-30 20:57:52 +00:00
sev_platform_shutdown ( NULL ) ;
2019-12-04 11:48:59 +05:30
sev - > state = SEV_STATE_UNINIT ;
2019-01-30 20:57:52 +00:00
}
2019-07-12 13:41:58 -07:00
if ( sev_version_greater_or_equal ( 0 , 15 ) & &
2019-12-04 11:48:59 +05:30
sev_update_firmware ( sev - > dev ) = = 0 )
2018-05-25 15:23:29 -05:00
sev_get_api_version ( ) ;
2020-04-21 12:44:49 -05:00
/* Obtain the TMR memory area for SEV-ES use */
tmr_page = alloc_pages ( GFP_KERNEL , get_order ( SEV_ES_TMR_SIZE ) ) ;
if ( tmr_page ) {
sev_es_tmr = page_address ( tmr_page ) ;
} else {
sev_es_tmr = NULL ;
dev_warn ( sev - > dev ,
" SEV: TMR allocation failed, SEV-ES support unavailable \n " ) ;
}
2017-12-04 10:57:28 -06:00
/* Initialize the platform */
rc = sev_platform_init ( & error ) ;
2019-10-17 22:35:11 +00:00
if ( rc & & ( error = = SEV_RET_SECURE_DATA_INVALID ) ) {
/*
* INIT command returned an integrity check failure
* status code , meaning that firmware load and
* validation of SEV related persistent data has
* failed and persistent state has been erased .
* Retrying INIT command here should succeed .
*/
2019-12-04 11:48:59 +05:30
dev_dbg ( sev - > dev , " SEV: retrying INIT command " ) ;
2019-10-17 22:35:11 +00:00
rc = sev_platform_init ( & error ) ;
}
2017-12-04 10:57:28 -06:00
if ( rc ) {
2019-12-04 11:48:59 +05:30
dev_err ( sev - > dev , " SEV: failed to INIT error %#x \n " , error ) ;
2019-04-08 20:42:55 +00:00
return ;
2017-12-04 10:57:28 -06:00
}
2019-12-04 11:48:59 +05:30
dev_info ( sev - > dev , " SEV API:%d.%d build:%d \n " , sev - > api_major ,
sev - > api_minor , sev - > build ) ;
2017-12-04 10:57:28 -06:00
return ;
err :
2019-12-04 11:48:59 +05:30
psp_master - > sev_data = NULL ;
2017-12-04 10:57:28 -06:00
}
2019-12-04 11:48:59 +05:30
void sev_pci_exit ( void )
2017-12-04 10:57:28 -06:00
{
2019-12-04 11:48:59 +05:30
if ( ! psp_master - > sev_data )
2017-12-04 10:57:28 -06:00
return ;
sev_platform_shutdown ( NULL ) ;
2020-04-21 12:44:49 -05:00
if ( sev_es_tmr ) {
/* The TMR area was encrypted, flush it from the cache */
wbinvd_on_all_cpus ( ) ;
free_pages ( ( unsigned long ) sev_es_tmr ,
get_order ( SEV_ES_TMR_SIZE ) ) ;
sev_es_tmr = NULL ;
}
2017-12-04 10:57:28 -06:00
}