Re: [RFC PATCH v2 26/32] kvm: svm: Add support for SEV LAUNCH_UPDATE_DATA command

From: Brijesh Singh
Date: Thu Mar 16 2017 - 14:20:30 EST



On 03/16/2017 05:48 AM, Paolo Bonzini wrote:


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(&current->mm->mmap_sem);
+ pinned = get_user_pages_fast(uaddr, npages, 1, pages);
+ up_read(&current->mm->mmap_sem);

get_user_pages_fast, like get_user_pages_unlocked, must be called
without mmap_sem held.

Sure.


+ 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.


Will do.

-Brijesh