lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <8e4c35e7-7a41-4f2d-b838-92811cfa71f2@amd.com>
Date: Thu, 24 Jul 2025 23:30:50 -0500
From: "Kalra, Ashish" <ashish.kalra@....com>
To: Mario Limonciello <superm1@...nel.org>, thomas.lendacky@....com,
 john.allen@....com, herbert@...dor.apana.org.au, davem@...emloft.net
Cc: seanjc@...gle.com, pbonzini@...hat.com, michael.roth@....com,
 linux-crypto@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH 2/2] crypto: ccp - Add AMD Seamless Firmware Servicing
 (SFS) driver

On 7/24/2025 10:32 PM, Mario Limonciello wrote:
> 
> 
> On 7/24/25 4:16 PM, Ashish Kalra wrote:
>> From: Ashish Kalra <ashish.kalra@....com>
>>
>> AMD Seamless Firmware Servicing (SFS) is a secure method to allow
>> non-persistent updates to running firmware and settings without
>> requiring BIOS reflash and/or system reset.
>>
>> SFS does not address anything that runs on the x86 processors and
>> it can be used to update ASP firmware, modules, register settings
>> and update firmware for other microprocessors like TMPM, etc.
>>
>> SFS driver support adds ioctl support to communicate the SFS
>> commands to the ASP/PSP by using the TEE mailbox interface.
>>
>> The Seamless Firmware Servicing (SFS) driver is added as a
>> PSP sub-device.
>>
>> For detailed information, please look at the SFS specifications:
>> https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/58604.pdf
>>
>> Signed-off-by: Ashish Kalra <ashish.kalra@....com>
>> ---
>>   drivers/crypto/ccp/Makefile         |   3 +-
>>   drivers/crypto/ccp/psp-dev.c        |  20 ++
>>   drivers/crypto/ccp/psp-dev.h        |   8 +-
>>   drivers/crypto/ccp/sfs.c            | 316 ++++++++++++++++++++++++++++
>>   drivers/crypto/ccp/sfs.h            |  53 +++++
>>   include/linux/psp-platform-access.h |   2 +
>>   include/uapi/linux/psp-sfs.h        |  87 ++++++++
>>   7 files changed, 487 insertions(+), 2 deletions(-)
>>   create mode 100644 drivers/crypto/ccp/sfs.c
>>   create mode 100644 drivers/crypto/ccp/sfs.h
>>   create mode 100644 include/uapi/linux/psp-sfs.h
>>
>> diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
>> index 394484929dae..9b876bfb1289 100644
>> --- a/drivers/crypto/ccp/Makefile
>> +++ b/drivers/crypto/ccp/Makefile
>> @@ -13,7 +13,8 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o \
>>                                      tee-dev.o \
>>                                      platform-access.o \
>>                                      dbc.o \
>> -                                   hsti.o
>> +                                   hsti.o \
>> +                   sfs.o
>>     obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
>>   ccp-crypto-objs := ccp-crypto-main.o \
>> diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
>> index 1c5a7189631e..8c4ad225ad67 100644
>> --- a/drivers/crypto/ccp/psp-dev.c
>> +++ b/drivers/crypto/ccp/psp-dev.c
>> @@ -17,6 +17,7 @@
>>   #include "psp-dev.h"
>>   #include "sev-dev.h"
>>   #include "tee-dev.h"
>> +#include "sfs.h"
>>   #include "platform-access.h"
>>   #include "dbc.h"
>>   #include "hsti.h"
>> @@ -182,6 +183,17 @@ static int psp_check_tee_support(struct psp_device *psp)
>>       return 0;
>>   }
>>   +static int psp_check_sfs_support(struct psp_device *psp)
>> +{
>> +    /* Check if device supports SFS feature */
>> +    if (!psp->capability.sev) {
> 
> Should this be psp->capability.sfs?

Yes, definately it should be psp->capability.sfs.

I don't know how did this got pushed, i have been testing with : 

static int psp_check_sfs_support(struct psp_device *psp)
{
        /* Check if device supports SFS feature */
        if (!psp->capability.sfs) {
                dev_dbg(psp->dev, "psp does not support SFS\n");
                return -ENODEV;
        }

        return 0;
}

I will push the correct function in the next version.

> 
>> +        dev_dbg(psp->dev, "psp does not support SFS\n");
>> +        return -ENODEV;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>>   static int psp_init(struct psp_device *psp)
>>   {
>>       int ret;
>> @@ -198,6 +210,12 @@ static int psp_init(struct psp_device *psp)
>>               return ret;
>>       }
>>   +    if (!psp_check_sfs_support(psp)) {
>> +        ret = sfs_dev_init(psp);
>> +        if (ret)
>> +            return ret;
>> +    }
>> +
>>       if (psp->vdata->platform_access) {
>>           ret = platform_access_dev_init(psp);
>>           if (ret)
>> @@ -302,6 +320,8 @@ void psp_dev_destroy(struct sp_device *sp)
>>         tee_dev_destroy(psp);
>>   +    sfs_dev_destroy(psp);
>> +
>>       dbc_dev_destroy(psp);
>>         platform_access_dev_destroy(psp);
>> diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
>> index e43ce87ede76..268c83f298cb 100644
>> --- a/drivers/crypto/ccp/psp-dev.h
>> +++ b/drivers/crypto/ccp/psp-dev.h
>> @@ -32,7 +32,8 @@ union psp_cap_register {
>>           unsigned int sev            :1,
>>                    tee            :1,
>>                    dbc_thru_ext        :1,
>> -                 rsvd1            :4,
>> +                 sfs            :1,
>> +                 rsvd1            :3,
>>                    security_reporting        :1,
>>                    fused_part            :1,
>>                    rsvd2            :1,
>> @@ -68,6 +69,7 @@ struct psp_device {
>>       void *tee_data;
>>       void *platform_access_data;
>>       void *dbc_data;
>> +    void *sfs_data;
>>         union psp_cap_register capability;
>>   };
>> @@ -118,12 +120,16 @@ struct psp_ext_request {
>>    * @PSP_SUB_CMD_DBC_SET_UID:        Set UID for DBC
>>    * @PSP_SUB_CMD_DBC_GET_PARAMETER:    Get parameter from DBC
>>    * @PSP_SUB_CMD_DBC_SET_PARAMETER:    Set parameter for DBC
>> + * @PSP_SUB_CMD_SFS_GET_FW_VERS:    Get firmware versions for ASP and other MP
>> + * @PSP_SUB_CMD_SFS_UPDATE:        Command to load, verify and execute SFS package
>>    */
>>   enum psp_sub_cmd {
>>       PSP_SUB_CMD_DBC_GET_NONCE    = PSP_DYNAMIC_BOOST_GET_NONCE,
>>       PSP_SUB_CMD_DBC_SET_UID        = PSP_DYNAMIC_BOOST_SET_UID,
>>       PSP_SUB_CMD_DBC_GET_PARAMETER    = PSP_DYNAMIC_BOOST_GET_PARAMETER,
>>       PSP_SUB_CMD_DBC_SET_PARAMETER    = PSP_DYNAMIC_BOOST_SET_PARAMETER,
>> +    PSP_SUB_CMD_SFS_GET_FW_VERS    = PSP_SFS_GET_FW_VERSIONS,
>> +    PSP_SUB_CMD_SFS_UPDATE        = PSP_SFS_UPDATE,
>>   };
>>     int psp_extended_mailbox_cmd(struct psp_device *psp, unsigned int timeout_msecs,
>> diff --git a/drivers/crypto/ccp/sfs.c b/drivers/crypto/ccp/sfs.c
>> new file mode 100644
>> index 000000000000..cbca01a884e1
>> --- /dev/null
>> +++ b/drivers/crypto/ccp/sfs.c
>> @@ -0,0 +1,316 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * AMD Secure Processor Seamless Firmware Servicing support.
>> + *
>> + * Copyright (C) 2023-2025 Advanced Micro Devices, Inc.
>> + *
>> + * Author: Ashish Kalra <ashish.kalra@....com>
>> + */
>> +
>> +#include <linux/firmware.h>
>> +
>> +#include "sfs.h"
>> +#include "sev-dev.h"
>> +
>> +#define SFS_DEFAULT_TIMEOUT        (10 * MSEC_PER_SEC)
>> +#define SFS_MAX_PAYLOAD_SIZE        (2 * 1024 * 1024)
>> +#define ORDER_2MB 9
>> +
>> +/* SFS Status values */
>> +#define SFS_SUCCESS            0x00
>> +#define SFS_INVALID_TOTAL_SIZE        0x02
>> +#define SFS_INVALID_PKG_SIZE        0x04
>> +#define SFS_DISABLED            0x05
>> +#define SFS_INVALID_CUST_SIGN        0x06
>> +#define SFS_INVALID_AMD_SIGN        0x07
>> +#define SFS_INTERNAL_ERROR        0x08
>> +#define SFS_CUST_SIGN_NOT_ALLOWED    0x09
>> +#define SFS_INVALID_BASE_PATCH_LVL    0x0A
>> +#define SFS_INVALID_CURR_PATCH_LVL    0x0B
>> +#define SFS_INVALID_NEW_PATCH_LVL    0x0C
>> +#define SFS_INVALID_SUBCOMMAND        0x0D
>> +#define SFS_PROTECTION_FAIL        0x0E
>> +#define SFS_BUSY            0x0F
>> +#define SFS_FW_VERSION_MISMATCH    0x10
>> +#define SFS_SYS_VERSION_MISMATCH    0x11
>> +#define SFS_SEV_STILL_INITIALIZED    0x12
>> +
>> +static bool sfs_initialized;
>> +
>> +static int send_sfs_cmd(struct psp_sfs_device *sfs_dev, int msg)
>> +{
>> +    int ret;
>> +
>> +    *sfs_dev->result = 0;
>> +    sfs_dev->command_hdr->ext_req.header.sub_cmd_id = msg;
>> +
>> +    ret = psp_extended_mailbox_cmd(sfs_dev->psp,
>> +                    SFS_DEFAULT_TIMEOUT,
>> +                    (struct psp_ext_request *)sfs_dev->command_hdr);
>> +    if (ret == -EIO) {
>> +        dev_dbg(sfs_dev->dev,
>> +             "msg 0x%x failed with PSP error: 0x%x\n",
>> +             msg, *sfs_dev->result);
>> +        dev_dbg(sfs_dev->dev,
>> +             "msg 0x%x extended status: 0x%x\n",
>> +             msg, *(u32 *)sfs_dev->payload);
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>> +static int send_sfs_get_fw_versions(struct psp_sfs_device *sfs_dev)
>> +{
>> +    int ret;
>> +
>> +    sfs_dev->payload_size = &sfs_dev->command_hdr->ext_req.header.payload_size;
>> +    sfs_dev->result = &sfs_dev->command_hdr->ext_req.header.status;
>> +    sfs_dev->payload = &sfs_dev->command_hdr->ext_req.buf;
>> +    sfs_dev->pkg_hdr = (void *)sfs_dev->command_hdr + PAGE_SIZE;
>> +    sfs_dev->header_size = sizeof(struct psp_ext_req_buffer_hdr);
>> +
>> +    /*
>> +     * SFS_GET_FW_VERSIONS command needs the output buffer to be
>> +     * initialized to 0xC7 in every byte.
>> +     */
>> +    memset(sfs_dev->pkg_hdr, 0xc7, PAGE_SIZE);
>> +    *sfs_dev->payload_size = 2 * PAGE_SIZE;
>> +
>> +    ret = send_sfs_cmd(sfs_dev, PSP_SFS_GET_FW_VERSIONS);
>> +
>> +    return ret;
>> +}
>> +
>> +static int send_sfs_update_package(struct psp_sfs_device *sfs_dev, char *payload_name)
>> +{
>> +    char payload_path[PAYLOAD_NAME_SIZE];
>> +    const struct firmware *firmware;
>> +    unsigned long package_size;
>> +    int ret;
>> +
>> +    sprintf(payload_path, "amd/%s", payload_name);
>> +
>> +    ret = firmware_request_nowarn(&firmware, payload_path, sfs_dev->dev);
>> +    if (ret < 0) {
>> +        dev_warn(sfs_dev->dev, "firmware request fail %d\n", ret);
>> +        return -ENOENT;
>> +    }
>> +
>> +    /* SFS Update Package should be 64KB aligned */
>> +    package_size = ALIGN(firmware->size + PAGE_SIZE, 0x10000U);
>> +
>> +    /*
>> +     * SFS command buffer is a pre-allocated 2MB buffer, fail update package
>> +     * if SFS payload is larger than the pre-allocated command buffer.
>> +     */
>> +    if (package_size > SFS_MAX_PAYLOAD_SIZE) {
>> +        dev_warn(sfs_dev->dev,
>> +             "SFS payload size %ld larger than maximum supported payload size of 2MB\n",
>> +             package_size);
>> +        return -ENOMEM;
>> +    }
>> +
>> +    sfs_dev->payload_size = &sfs_dev->command_hdr->ext_req.header.payload_size;
>> +    sfs_dev->result = &sfs_dev->command_hdr->ext_req.header.status;
>> +    sfs_dev->payload = &sfs_dev->command_hdr->ext_req.buf;
>> +    sfs_dev->pkg_hdr = (void *)sfs_dev->command_hdr + PAGE_SIZE;
>> +    sfs_dev->header_size = sizeof(struct psp_ext_req_buffer_hdr);
>> +
>> +    /*
>> +     * Copy firmware data to a kernel allocated contiguous
>> +     * memory region.
>> +     */
>> +    memcpy(sfs_dev->pkg_hdr, firmware->data, firmware->size);
>> +    *sfs_dev->payload_size = package_size;
>> +
>> +    ret = send_sfs_cmd(sfs_dev, PSP_SFS_UPDATE);
>> +
>> +    release_firmware(firmware);
>> +    return ret;
>> +}
>> +
>> +static long sfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>> +{
>> +    struct psp_device *psp_master = psp_get_master_device();
>> +    void __user *argp = (void __user *)arg;
>> +    char payload_name[PAYLOAD_NAME_SIZE];
>> +    struct psp_sfs_device *sfs_dev;
>> +    int ret;
>> +
>> +    if (!psp_master || !psp_master->sfs_data)
>> +        return -ENODEV;
>> +    sfs_dev = psp_master->sfs_data;
>> +
>> +    if (!sfs_initialized)
>> +        return -EINVAL;
>> +
>> +    mutex_lock(&sfs_dev->ioctl_mutex);
> 
> As it's new code, how about using guard(mutex) instead?  Then you don't need to have goto unlock in the failure cases and can just return the error directly.
> 

Sure, will do that.

Thanks,
Ashish

>> +
>> +    switch (cmd) {
>> +    case SFSIOCFWVERS:
>> +        dev_dbg(sfs_dev->dev, "in SFSIOCFWVERS\n");
>> +
>> +        ret = send_sfs_get_fw_versions(sfs_dev);
>> +        if (ret && ret != -EIO)
>> +            goto unlock;
>> +        /*
>> +         * return SFS status and extended status back to userspace
>> +         * if PSP status indicated command error.
>> +         */
>> +        if (copy_to_user(argp, sfs_dev->pkg_hdr, PAGE_SIZE))
>> +            ret = -EFAULT;
>> +        if (copy_to_user(argp + PAGE_SIZE, sfs_dev->result, sizeof(u32)))
>> +            ret = -EFAULT;
>> +        if (copy_to_user(argp + PAGE_SIZE + sizeof(u32), sfs_dev->payload, sizeof(u32)))
>> +            ret = -EFAULT;
>> +        break;
>> +    case SFSIOCUPDATEPKG:
>> +        dev_dbg(sfs_dev->dev, "in SFSIOCUPDATEPKG\n");
>> +
>> +        if (copy_from_user(payload_name, argp, PAYLOAD_NAME_SIZE)) {
>> +            ret = -EFAULT;
>> +            goto unlock;
>> +        }
>> +
>> +        ret = send_sfs_update_package(sfs_dev, payload_name);
>> +        if (ret && ret != -EIO)
>> +            goto unlock;
>> +        /*
>> +         * return SFS status and extended status back to userspace
>> +         * if PSP status indicated command error.
>> +         */
>> +        if (copy_to_user(argp + PAYLOAD_NAME_SIZE, sfs_dev->result, sizeof(u32)))
>> +            ret = -EFAULT;
>> +        if (copy_to_user(argp + PAYLOAD_NAME_SIZE + sizeof(u32), sfs_dev->payload,
>> +                 sizeof(u32)))
>> +            ret = -EFAULT;
>> +        break;
>> +    default:
>> +        ret = -EINVAL;
>> +    }
>> +
>> +unlock:
>> +    mutex_unlock(&sfs_dev->ioctl_mutex);
>> +
>> +    return ret;
>> +}
>> +
>> +static const struct file_operations sfs_fops = {
>> +    .owner    = THIS_MODULE,
>> +    .unlocked_ioctl = sfs_ioctl,
>> +};
>> +
>> +void sfs_dev_destroy(struct psp_device *psp)
>> +{
>> +    struct psp_sfs_device *sfs_dev = psp->sfs_data;
>> +    int ret;
>> +
>> +    if (!sfs_dev)
>> +        return;
>> +
>> +    /*
>> +     * TODO: free pre-allocated 2MB command buffer,
>> +     * if SEV-SNP is initialized the command buffer has
>> +     * been marked HV_Fixed and HV_Fixed pages remain
>> +     * in that state till system reset, they cannot be
>> +     * released back to the page allocator.
>> +     *
>> +     */
>> +    snp_delete_hypervisor_fixed_pages_list(page_to_pfn(sfs_dev->page) << PAGE_SHIFT);
>> +
>> +    ret = set_memory_wb((unsigned long)page_address(sfs_dev->page), 512);
>> +    if (ret)
>> +        dev_dbg(sfs_dev->dev, "set memory wb failed\n");
>> +
>> +    sfs_initialized = false;
>> +    misc_deregister(&sfs_dev->char_dev);
>> +    mutex_destroy(&sfs_dev->ioctl_mutex);
>> +    psp->sfs_data = NULL;
>> +}
>> +
>> +int sfs_dev_init(struct psp_device *psp)
>> +{
>> +    struct device *dev = psp->dev;
>> +    struct psp_sfs_device *sfs_dev;
>> +    struct page *page;
>> +    u64 cmd_buf_paddr;
>> +    int ret;
>> +
>> +    /*
>> +     * SFS feature support can be detected on multiple devices but the SFS
>> +     * FW commands must be issued on the master. During probe, we do not
>> +     * know the master hence we create /dev/sfs on the first device probe.
>> +     */
>> +    if (sfs_initialized)
>> +        return 0;
>> +
>> +    sfs_dev = devm_kzalloc(dev, sizeof(*sfs_dev), GFP_KERNEL);
>> +    if (!sfs_dev)
>> +        return -ENOMEM;
>> +
>> +    BUILD_BUG_ON(sizeof(struct sfs_command) > PAGE_SIZE);
>> +
>> +    /*
>> +     * Pre-allocate static 2MB command buffer for all SFS commands.
>> +     */
>> +    page = alloc_pages(GFP_KERNEL | __GFP_ZERO, ORDER_2MB);
>> +    if (!page)
>> +        return -ENOMEM;
>> +    sfs_dev->page = page;
>> +    sfs_dev->command_hdr = page_address(page);
>> +    cmd_buf_paddr = page_to_pfn(sfs_dev->page) << PAGE_SHIFT;
>> +
>> +    /*
>> +     * If SEV-SNP is enabled the SFS command buffer needs to
>> +     * transitioned to HV_Fixed page state.
>> +     */
>> +    dev_dbg(sfs_dev->dev, "cmdbuf page pa 0x%llx to be marked as HV_Fixed\n",
>> +        cmd_buf_paddr);
>> +
>> +    ret = snp_insert_hypervisor_fixed_pages_list(cmd_buf_paddr, 512);
>> +    if (ret) {
>> +        dev_dbg(sfs_dev->dev, "cmdbuf page failed insertion in HV-Fixed page list\n");
>> +        goto cleanup_cmd_buf;
>> +    }
>> +
>> +    /*
>> +     * Buffers used for communication with different processors, x86 to ASP
>> +     * in this case must be mapped as non-cacheable.
>> +     */
>> +    ret = set_memory_uc((unsigned long)page_address(page), 512);
>> +    if (ret) {
>> +        dev_dbg(sfs_dev->dev, "set memory uc failed\n");
>> +        goto cleanup_cmd_buf_after_hv_fixed;
>> +    }
>> +
>> +    dev_dbg(sfs_dev->dev, "cmdbuf page va 0x%lx marked as UnCacheable\n",
>> +        (unsigned long)sfs_dev->command_hdr);
>> +
>> +    psp->sfs_data = sfs_dev;
>> +    sfs_dev->dev = dev;
>> +    sfs_dev->psp = psp;
>> +
>> +    dev_dbg(sfs_dev->dev, "seamless firmware serviving support is available\n");
> 
> servicing
> 
>> +
>> +    sfs_dev->char_dev.minor = MISC_DYNAMIC_MINOR;
>> +    sfs_dev->char_dev.name = "sfs";
>> +    sfs_dev->char_dev.fops = &sfs_fops;
>> +    sfs_dev->char_dev.mode = 0600;
>> +    ret = misc_register(&sfs_dev->char_dev);
>> +    if (ret)
>> +        goto cleanup_cmd_buf_after_hv_fixed;
>> +
>> +    mutex_init(&sfs_dev->ioctl_mutex);
>> +    sfs_initialized = true;
>> +
>> +    return 0;
>> +
>> +cleanup_cmd_buf_after_hv_fixed:
>> +    snp_delete_hypervisor_fixed_pages_list(cmd_buf_paddr);
>> +cleanup_cmd_buf:
>> +    __free_pages(page, ORDER_2MB);
>> +    psp->sfs_data = NULL;
>> +    devm_kfree(dev, sfs_dev);
>> +
>> +    return ret;
>> +}
>> diff --git a/drivers/crypto/ccp/sfs.h b/drivers/crypto/ccp/sfs.h
>> new file mode 100644
>> index 000000000000..89b7792af076
>> --- /dev/null
>> +++ b/drivers/crypto/ccp/sfs.h
>> @@ -0,0 +1,53 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * AMD Platform Security Processor (PSP) Seamless Firmware (SFS) Support.
>> + *
>> + * Copyright (C) 2023-2025 Advanced Micro Devices, Inc.
>> + *
>> + * Author: Ashish Kalra <ashish.kalra@....com>
>> + */
>> +
>> +#ifndef __SFS_H__
>> +#define __SFS_H__
>> +
>> +#include <uapi/linux/psp-sfs.h>
>> +
>> +#include <linux/device.h>
>> +#include <linux/miscdevice.h>
>> +#include <linux/psp-sev.h>
>> +#include <linux/psp-platform-access.h>
>> +#include <linux/set_memory.h>
>> +
>> +#include <asm/sev.h>
>> +
>> +#include "psp-dev.h"
>> +
>> +struct psp_sfs_device {
>> +    struct device *dev;
>> +    struct psp_device *psp;
>> +
>> +    struct sfs_command *command_hdr;
>> +
>> +    struct mutex ioctl_mutex;
>> +
>> +    struct miscdevice char_dev;
>> +
>> +    struct page *page;
>> +
>> +    /* used to abstract communication path */
>> +    u32    header_size;
>> +    u32    *payload_size;
>> +    u32    *result;
>> +    void    *payload;
>> +    void    *pkg_hdr;
>> +};
>> +
>> +struct sfs_command {
>> +    struct psp_ext_request ext_req;
>> +};
>> +
>> +void sfs_dev_destroy(struct psp_device *psp);
>> +int sfs_dev_init(struct psp_device *psp);
>> +void sfs_pci_init(void);
>> +
>> +#endif /* __SFS_H__ */
>> diff --git a/include/linux/psp-platform-access.h b/include/linux/psp-platform-access.h
>> index 1504fb012c05..540abf7de048 100644
>> --- a/include/linux/psp-platform-access.h
>> +++ b/include/linux/psp-platform-access.h
>> @@ -7,6 +7,8 @@
>>     enum psp_platform_access_msg {
>>       PSP_CMD_NONE            = 0x0,
>> +    PSP_SFS_GET_FW_VERSIONS,
>> +    PSP_SFS_UPDATE,
>>       PSP_CMD_HSTI_QUERY        = 0x14,
>>       PSP_I2C_REQ_BUS_CMD        = 0x64,
>>       PSP_DYNAMIC_BOOST_GET_NONCE,
>> diff --git a/include/uapi/linux/psp-sfs.h b/include/uapi/linux/psp-sfs.h
>> new file mode 100644
>> index 000000000000..e752fa041683
>> --- /dev/null
>> +++ b/include/uapi/linux/psp-sfs.h
>> @@ -0,0 +1,87 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
>> +/*
>> + * Userspace interface for AMD Seamless Firmware Servicing (SFS)
>> + *
>> + * Copyright (C) 2023-2025 Advanced Micro Devices, Inc.
>> + *
>> + * Author: Ashish Kalra <ashish.kalra@....com>
>> + */
>> +
>> +#ifndef __PSP_SFS_USER_H__
>> +#define __PSP_SFS_USER_H__
>> +
>> +#include <linux/types.h>
>> +
>> +/**
>> + * SFS: AMD Seamless Firmware Support (SFS) interface
>> + */
>> +
>> +#define PAYLOAD_NAME_SIZE        64
>> +#define TEE_EXT_CMD_BUFFER_SIZE    4096
>> +
>> +/**
>> + * struct sfs_user_get_fw_versions - get current level of base firmware (output).
>> + * @blob:                  current level of base firmware for ASP and patch levels (input/output).
>> + * @sfs_status:            32-bit SFS status value (output).
>> + * @sfs_extended_status:   32-bit SFS extended status value (output).
>> + */
>> +struct sfs_user_get_fw_versions {
>> +    __u8    blob[TEE_EXT_CMD_BUFFER_SIZE];
>> +    __u32    sfs_status;
>> +    __u32    sfs_extended_status;
>> +} __packed;
>> +
>> +/**
>> + * struct sfs_user_update_package - update SFS package (input).
>> + * @payload_name:          name of SFS package to load, verify and execute (input).
>> + * @sfs_status:            32-bit SFS status value (output).
>> + * @sfs_extended_status:   32-bit SFS extended status value (output).
>> + */
>> +struct sfs_user_update_package {
>> +    char    payload_name[PAYLOAD_NAME_SIZE];
>> +    __u32    sfs_status;
>> +    __u32    sfs_extended_status;
>> +} __packed;
>> +
>> +/**
>> + * Seamless Firmware Support (SFS) IOC
>> + *
>> + * possible return codes for all SFS IOCTLs:
>> + *  0:          success
>> + *  -EINVAL:    invalid input
>> + *  -E2BIG:     excess data passed
>> + *  -EFAULT:    failed to copy to/from userspace
>> + *  -EBUSY:     mailbox in recovery or in use
>> + *  -ENODEV:    driver not bound with PSP device
>> + *  -EACCES:    request isn't authorized
>> + *  -EINVAL:    invalid parameter
>> + *  -ETIMEDOUT: request timed out
>> + *  -EAGAIN:    invalid request for state machine
>> + *  -ENOENT:    not implemented
>> + *  -ENFILE:    overflow
>> + *  -EPERM:     invalid signature
>> + *  -EIO:       unknown error
>> + */
>> +#define SFS_IOC_TYPE    'S'
>> +
>> +/**
>> + * SFSIOCFWVERS - returns blob containing FW versions
>> + *                ASP provides the current level of Base Firmware for the ASP
>> + *                and the other microprocessors as well as current patch
>> + *                level(s).
>> + */
>> +#define SFSIOCFWVERS    _IOWR(SFS_IOC_TYPE, 0x1, struct sfs_user_get_fw_versions)
>> +
>> +/**
>> + * SFSIOCUPDATEPKG - updates package/payload
>> + *                   ASP loads, verifies and executes the SFS package.
>> + *                   By default, the SFS package/payload is loaded from
>> + *                   /lib/firmware/amd, but alternative firmware loading
>> + *                   path can be specified using kernel parameter
>> + *                   firmware_class.path or the firmware loading path
>> + *                   can be customized using sysfs file:
>> + *                   /sys/module/firmware_class/parameters/path.
>> + */
>> +#define SFSIOCUPDATEPKG    _IOWR(SFS_IOC_TYPE, 0x2, struct sfs_user_update_package)
>> +
>> +#endif /* __PSP_SFS_USER_H__ */
> 


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ