Re: [RFC PATCH v2 26/32] kvm: svm: Add support for SEV LAUNCH_UPDATE_DATA command
From: Paolo Bonzini <pbonzini@redhat.com>
Date: 2017-03-16 10:49:04
On 02/03/2017 16:17, Brijesh Singh wrote:
+static struct page **sev_pin_memory(unsigned long uaddr, unsigned long ulen,
+ unsigned long *n)
+{
+ struct page **pages;
+ int first, last;
+ unsigned long npages, pinned;
+
+ /* Get number of pages */
+ first = (uaddr & PAGE_MASK) >> PAGE_SHIFT;
+ last = ((uaddr + ulen - 1) & PAGE_MASK) >> PAGE_SHIFT;
+ npages = (last - first + 1);
+
+ pages = kzalloc(npages * sizeof(struct page *), GFP_KERNEL);
+ if (!pages)
+ return NULL;
+
+ /* pin the user virtual address */
+ down_read(¤t->mm->mmap_sem);
+ pinned = get_user_pages_fast(uaddr, npages, 1, pages);
+ up_read(¤t->mm->mmap_sem);get_user_pages_fast, like get_user_pages_unlocked, must be called without mmap_sem held.
+ if (pinned != npages) {
+ printk(KERN_ERR "SEV: failed to pin %ld pages (got %ld)\n",
+ npages, pinned);
+ goto err;
+ }
+
+ *n = npages;
+ return pages;
+err:
+ if (pinned > 0)
+ release_pages(pages, pinned, 0);
+ kfree(pages);
+
+ return NULL;
+}
+ /* the array of pages returned by get_user_pages() is a page-aligned
+ * memory. Since the user buffer is probably not page-aligned, we need
+ * to calculate the offset within a page for first update entry.
+ */
+ offset = uaddr & (PAGE_SIZE - 1);
+ len = min_t(size_t, (PAGE_SIZE - offset), ulen);
+ ulen -= len;
+
+ /* update first page -
+ * special care need to be taken for the first page because we might
+ * be dealing with offset within the page
+ */No need to special case the first page; just set "offset = 0" inside the loop after the first iteration. Paolo
+ data->handle = sev_get_handle(kvm);
+ data->length = len;
+ data->address = __sev_page_pa(inpages[0]) + offset;
+ ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_DATA,
+ data, &argp->error);
+ if (ret)
+ goto err_3;
+
+ /* update remaining pages */
+ for (i = 1; i < nr_pages; i++) {
+
+ len = min_t(size_t, PAGE_SIZE, ulen);
+ ulen -= len;
+ data->length = len;
+ data->address = __sev_page_pa(inpages[i]);
+ ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_DATA,
+ data, &argp->error);
+ if (ret)
+ goto err_3;
+ }