lkml.org 
[lkml]   [2021]   [Sep]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH Part1 v5 36/38] virt: Add SEV-SNP guest driver
    On Fri, Aug 20, 2021 at 10:19:31AM -0500, Brijesh Singh wrote:
    > +===================================================================
    > +The Definitive SEV Guest API Documentation
    > +===================================================================
    > +
    > +1. General description
    > +======================
    > +
    > +The SEV API is a set of ioctls that are issued to by the guest or

    issued to by?

    Issued by the guest or hypervisor, you mean..

    > +hypervisor to get or set certain aspect of the SEV virtual machine.
    > +The ioctls belong to the following classes:
    > +
    > + - Hypervisor ioctls: These query and set global attributes which affect the
    > + whole SEV firmware. These ioctl is used by platform provision tools.

    "These ioctls are used ... "

    > +
    > + - Guest ioctls: These query and set attribute of the SEV virtual machine.

    "... attributes... "

    > +
    > +2. API description
    > +==================
    > +
    > +This section describes ioctls that can be used to query or set SEV guests.
    > +For each ioctl, the following information is provided along with a
    > +description:
    > +
    > + Technology:
    > + which SEV techology provides this ioctl. sev, sev-es, sev-snp or all.
    > +
    > + Type:
    > + hypervisor or guest. The ioctl can be used inside the guest or the
    > + hypervisor.
    > +
    > + Parameters:
    > + what parameters are accepted by the ioctl.
    > +
    > + Returns:
    > + the return value. General error numbers (ENOMEM, EINVAL)
    > + are not detailed, but errors with specific meanings are.
    > +
    > +The guest ioctl should be called to /dev/sev-guest device. The ioctl accepts

    s/called to/issued on a file descriptor of the/

    > +struct snp_user_guest_request. The input and output structure is specified
    > +through the req_data and resp_data field respectively. If the ioctl fails
    > +to execute due to the firmware error, then fw_err code will be set.

    "... due to a ... "

    > +
    > +::
    > + struct snp_user_guest_request {

    So you said earlier:

    > I followed the naming convension you recommended during the initial SEV driver
    > developement. IIRC, the main reason for us having to add "user" in it because
    > we wanted to distinguious that this structure is not exactly same as the what
    > is defined in the SEV-SNP firmware spec.

    but looking at the current variant in the code, the structure in the SNP spec is

    Table 91. Layout of the CMDBUF_SNP_GUEST_REQUEST Structure

    which corresponds to struct snp_guest_request_data so you can call this one:

    struct snp_guest_request_ioctl

    and then it is perfectly clear what is what.

    > + /* Request and response structure address */
    > + __u64 req_data;
    > + __u64 resp_data;
    > +
    > + /* firmware error code on failure (see psp-sev.h) */
    > + __u64 fw_err;
    > + };
    > +
    > +2.1 SNP_GET_REPORT
    > +------------------
    > +
    > +:Technology: sev-snp
    > +:Type: guest ioctl
    > +:Parameters (in): struct snp_report_req
    > +:Returns (out): struct snp_report_resp on success, -negative on error
    > +
    > +The SNP_GET_REPORT ioctl can be used to query the attestation report from the
    > +SEV-SNP firmware. The ioctl uses the SNP_GUEST_REQUEST (MSG_REPORT_REQ) command
    > +provided by the SEV-SNP firmware to query the attestation report.
    > +
    > +On success, the snp_report_resp.data will contains the report. The report

    "... will contain... "

    > +format is described in the SEV-SNP specification. See the SEV-SNP specification
    > +for further details.

    "... which can be found at https://developer.amd.com/sev/."

    assuming that URL will keep its validity in the foreseeable future.

    > +static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
    > +{
    > + struct snp_guest_dev *snp_dev = to_snp_dev(file);
    > + void __user *argp = (void __user *)arg;
    > + struct snp_user_guest_request input;
    > + int ret = -ENOTTY;
    > +
    > + if (copy_from_user(&input, argp, sizeof(input)))
    > + return -EFAULT;
    > +
    > + mutex_lock(&snp_cmd_mutex);
    > +
    > + switch (ioctl) {
    > + case SNP_GET_REPORT: {
    > + ret = get_report(snp_dev, &input);
    > + break;
    > + }

    No need for those {} brackets around the case.

    > + default:
    > + break;
    > + }
    > +
    > + mutex_unlock(&snp_cmd_mutex);
    > +
    > + if (copy_to_user(argp, &input, sizeof(input)))
    > + return -EFAULT;
    > +
    > + return ret;
    > +}
    > +
    > +static void free_shared_pages(void *buf, size_t sz)
    > +{
    > + unsigned int npages = PAGE_ALIGN(sz) >> PAGE_SHIFT;
    > +
    > + /* If fail to restore the encryption mask then leak it. */
    > + if (set_memory_encrypted((unsigned long)buf, npages))

    Hmm, this sounds like an abnormal condition about which we should at
    least warn...

    > + return;
    > +
    > + __free_pages(virt_to_page(buf), get_order(sz));
    > +}
    > +
    > +static void *alloc_shared_pages(size_t sz)
    > +{
    > + unsigned int npages = PAGE_ALIGN(sz) >> PAGE_SHIFT;
    > + struct page *page;
    > + int ret;
    > +
    > + page = alloc_pages(GFP_KERNEL_ACCOUNT, get_order(sz));
    > + if (IS_ERR(page))
    > + return NULL;
    > +
    > + ret = set_memory_decrypted((unsigned long)page_address(page), npages);
    > + if (ret) {
    > + __free_pages(page, get_order(sz));
    > + return NULL;
    > + }
    > +
    > + return page_address(page);
    > +}
    > +
    > +static const struct file_operations snp_guest_fops = {
    > + .owner = THIS_MODULE,
    > + .unlocked_ioctl = snp_guest_ioctl,
    > +};
    > +
    > +static int __init snp_guest_probe(struct platform_device *pdev)
    > +{
    > + struct snp_guest_platform_data *data;
    > + struct device *dev = &pdev->dev;
    > + struct snp_guest_dev *snp_dev;
    > + struct miscdevice *misc;
    > + int ret;
    > +
    > + if (!dev->platform_data)
    > + return -ENODEV;
    > +
    > + data = (struct snp_guest_platform_data *)dev->platform_data;
    > + vmpck_id = data->vmpck_id;
    > +
    > + snp_dev = devm_kzalloc(&pdev->dev, sizeof(struct snp_guest_dev), GFP_KERNEL);
    > + if (!snp_dev)
    > + return -ENOMEM;
    > +
    > + platform_set_drvdata(pdev, snp_dev);
    > + snp_dev->dev = dev;
    > +
    > + snp_dev->crypto = init_crypto(snp_dev, data->vmpck, sizeof(data->vmpck));
    > + if (!snp_dev->crypto)
    > + return -EIO;

    I guess you should put the crypto init...

    > +
    > + /* Allocate the shared page used for the request and response message. */
    > + snp_dev->request = alloc_shared_pages(sizeof(struct snp_guest_msg));
    > + if (IS_ERR(snp_dev->request)) {
    > + ret = PTR_ERR(snp_dev->request);
    > + goto e_free_crypto;
    > + }
    > +
    > + snp_dev->response = alloc_shared_pages(sizeof(struct snp_guest_msg));
    > + if (IS_ERR(snp_dev->response)) {
    > + ret = PTR_ERR(snp_dev->response);
    > + goto e_free_req;
    > + }

    ... here, after the page allocation to save yourself all the setup work
    if the shared pages allocation fails.

    > +
    > + misc = &snp_dev->misc;
    > + misc->minor = MISC_DYNAMIC_MINOR;
    > + misc->name = DEVICE_NAME;
    > + misc->fops = &snp_guest_fops;
    > +
    > + return misc_register(misc);
    > +
    > +e_free_req:
    > + free_shared_pages(snp_dev->request, sizeof(struct snp_guest_msg));
    > +
    > +e_free_crypto:
    > + deinit_crypto(snp_dev->crypto);
    > +
    > + return ret;
    > +}

    --
    Regards/Gruss,
    Boris.

    https://people.kernel.org/tglx/notes-about-netiquette

    \
     
     \ /
      Last update: 2021-09-06 19:39    [W:2.538 / U:0.016 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site