From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on archive.lwn.net X-Spam-Level: X-Spam-Status: No, score=-5.6 required=5.0 tests=DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by archive.lwn.net (Postfix) with ESMTP id 667D57D87A for ; Fri, 31 Aug 2018 08:49:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727725AbeHaMzG (ORCPT ); Fri, 31 Aug 2018 08:55:06 -0400 Received: from mail-ed1-f68.google.com ([209.85.208.68]:45333 "EHLO mail-ed1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727583AbeHaMzF (ORCPT ); Fri, 31 Aug 2018 08:55:05 -0400 Received: by mail-ed1-f68.google.com with SMTP id p52-v6so8470967eda.12 for ; Fri, 31 Aug 2018 01:48:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ffwll.ch; s=google; h=sender:date:from:to:cc:subject:message-id:mail-followup-to :references:mime-version:content-disposition:in-reply-to:user-agent; bh=OOkjeJbKYJRTqA6DPOeq3z2TGatJZJErrowH+Jm+T+k=; b=eTFO1SuIaSjT4UPWMWyV8uobvzVjg9skZ+FeaR5JeKfP7fDafi0qa/dmiYk4mxNfex iNZPFXg9rdMo3SXYFmsPIJn0O6ZZEEoI52VHJ6FkPbgxWOdU759qxBZokN6tETln4nni NPEo92t+KnEkR9+SC0PxR4ETX6rLUdusJD8rg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :mail-followup-to:references:mime-version:content-disposition :in-reply-to:user-agent; bh=OOkjeJbKYJRTqA6DPOeq3z2TGatJZJErrowH+Jm+T+k=; b=luwySpSo4ZFrjNrJFWAcrRhYeIvCOoI6di7Sw0l2yrthV7AonsPERSsvPouea8p+Kf jy4O/ZosxvoIcn8KDVYII7zyRHiPOONr3bI9kNOVuEU6e/1xTzTKcDpLAGuLkImEvJIE WA2UYMGKAXwR8y9Fs829dP/RuVs3gtzesf3Rd4LpKfcoU4XTwD/oRv+QCXH0K4dFyhtJ L0bIK9AqPnRmifoS+TBEnbLJs8sRnCIGS3UZNWtvo8m1tFSDbkCfMBJ0HaZlDebpTTCK 7xyfW7s8HpYegNH/aHsU7dbHrjVXJ37b2PEIg0d+iz5XTmWetVRvA68C5ceUORxSxhAY su/w== X-Gm-Message-State: APzg51BdaBNxxjG/BnXgszgDwBw6YjFcgd2LFf16HL0Yo/Tgf0OT3qA3 8pZLY/zdes+Wonk3ISsq1ILSJ5E/5Y1BLw== X-Google-Smtp-Source: ANB0VdZ6iD5vQMr+LkqEJ14BD4Zu4Wj5tkfdDXAi9qHoet1UxoLpEXrw3VXJ/IveFJt66TvuhAeZbA== X-Received: by 2002:a50:984b:: with SMTP id h11-v6mr16731294edb.26.1535705318365; Fri, 31 Aug 2018 01:48:38 -0700 (PDT) Received: from phenom.ffwll.local (212-51-149-109.fiber7.init7.net. [212.51.149.109]) by smtp.gmail.com with ESMTPSA id j23-v6sm4047594edh.29.2018.08.31.01.48.36 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 31 Aug 2018 01:48:36 -0700 (PDT) Date: Fri, 31 Aug 2018 10:48:34 +0200 From: Daniel Vetter To: Gerd Hoffmann Cc: dri-devel@lists.freedesktop.org, David Airlie , Tomeu Vizoso , Laurent Pinchart , Daniel Vetter , Jonathan Corbet , Sumit Semwal , Shuah Khan , "open list:DOCUMENTATION" , open list , "open list:DMA BUFFER SHARING FRAMEWORK" , "moderated list:DMA BUFFER SHARING FRAMEWORK" , "open list:KERNEL SELFTEST FRAMEWORK" Subject: Re: [PATCH v7] Add udmabuf misc device Message-ID: <20180831084834.GP21634@phenom.ffwll.local> Mail-Followup-To: Gerd Hoffmann , dri-devel@lists.freedesktop.org, David Airlie , Tomeu Vizoso , Laurent Pinchart , Jonathan Corbet , Sumit Semwal , Shuah Khan , "open list:DOCUMENTATION" , open list , "open list:DMA BUFFER SHARING FRAMEWORK" , "moderated list:DMA BUFFER SHARING FRAMEWORK" , "open list:KERNEL SELFTEST FRAMEWORK" References: <20180827093444.23623-1-kraxel@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20180827093444.23623-1-kraxel@redhat.com> X-Operating-System: Linux phenom 4.14.0-3-amd64 User-Agent: Mutt/1.10.0 (2018-05-17) Sender: linux-doc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-doc@vger.kernel.org On Mon, Aug 27, 2018 at 11:34:44AM +0200, Gerd Hoffmann wrote: > A driver to let userspace turn memfd regions into dma-bufs. > > Use case: Allows qemu create dmabufs for the vga framebuffer or > virtio-gpu ressources. Then they can be passed around to display > those guest things on the host. To spice client for classic full > framebuffer display, and hopefully some day to wayland server for > seamless guest window display. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 ++++++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 16 ++ > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 447 insertions(+) > create mode 100644 include/uapi/linux/udmabuf.h > create mode 100644 drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile > > diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt > index 13a7c999c0..f2ac672eb7 100644 > --- a/Documentation/ioctl/ioctl-number.txt > +++ b/Documentation/ioctl/ioctl-number.txt > @@ -272,6 +272,7 @@ Code Seq#(hex) Include File Comments > 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM > 'u' 00-1F linux/smb_fs.h gone > 'u' 20-3F linux/uvcvideo.h USB video class host driver > +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device > 'v' 00-1F linux/ext2_fs.h conflict! > 'v' 00-1F linux/fs.h conflict! > 'v' 00-0F linux/sonypi.h conflict! > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ > +#ifndef _UAPI_LINUX_UDMABUF_H > +#define _UAPI_LINUX_UDMABUF_H > + > +#include > +#include > + > +#define UDMABUF_FLAGS_CLOEXEC 0x01 > + > +struct udmabuf_create { > + __u32 memfd; > + __u32 flags; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) > + > +#endif /* _UAPI_LINUX_UDMABUF_H */ > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct udmabuf { > + u32 pagecount; > + struct page **pages; > +}; > + > +static int udmabuf_vm_fault(struct vm_fault *vmf) > +{ > + struct vm_area_struct *vma = vmf->vma; > + struct udmabuf *ubuf = vma->vm_private_data; > + > + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > + return VM_FAULT_SIGBUS; > + > + vmf->page = ubuf->pages[vmf->pgoff]; > + get_page(vmf->page); > + return 0; > +} > + > +static const struct vm_operations_struct udmabuf_vm_ops = { > + .fault = udmabuf_vm_fault, > +}; > + > +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) > +{ > + struct udmabuf *ubuf = buf->priv; > + > + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) > + return -EINVAL; > + > + vma->vm_ops = &udmabuf_vm_ops; > + vma->vm_private_data = ubuf; > + return 0; > +} > + > +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, > + enum dma_data_direction direction) > +{ > + struct udmabuf *ubuf = at->dmabuf->priv; > + struct sg_table *sg; > + > + sg = kzalloc(sizeof(*sg), GFP_KERNEL); > + if (!sg) > + goto err1; > + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, > + 0, ubuf->pagecount << PAGE_SHIFT, > + GFP_KERNEL) < 0) > + goto err2; > + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) > + goto err3; > + > + return sg; > + > +err3: > + sg_free_table(sg); > +err2: > + kfree(sg); > +err1: > + return ERR_PTR(-ENOMEM); > +} > + > +static void unmap_udmabuf(struct dma_buf_attachment *at, > + struct sg_table *sg, > + enum dma_data_direction direction) > +{ > + sg_free_table(sg); > + kfree(sg); > +} > + > +static void release_udmabuf(struct dma_buf *buf) > +{ > + struct udmabuf *ubuf = buf->priv; > + pgoff_t pg; > + > + for (pg = 0; pg < ubuf->pagecount; pg++) > + put_page(ubuf->pages[pg]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) > +{ > + struct udmabuf *ubuf = buf->priv; > + struct page *page = ubuf->pages[page_num]; > + > + return kmap(page); > +} > + > +static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; > + > + exp_info.ops = &udmabuf_ops; > + exp_info.size = ubuf->pagecount << PAGE_SHIFT; > + exp_info.priv = ubuf; > + > + buf = dma_buf_export(&exp_info); > + if (IS_ERR(buf)) { > + ret = PTR_ERR(buf); > + goto err_put_pages; > + } > + > + flags = 0; > + if (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + return ret; > +} > + > +static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, > + unsigned long arg) > +{ > + long ret; > + > + switch (ioctl) { > + case UDMABUF_CREATE: > + ret = udmabuf_ioctl_create(filp, arg); > + break; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(filp, arg); > + break; > + default: > + ret = -EINVAL; > + break; > + } > + return ret; > +} > + > +static const struct file_operations udmabuf_fops = { > + .owner = THIS_MODULE, > + .unlocked_ioctl = udmabuf_ioctl, > +}; > + > +static struct miscdevice udmabuf_misc = { > + .minor = MISC_DYNAMIC_MINOR, > + .name = "udmabuf", > + .fops = &udmabuf_fops, > +}; > + > +static int __init udmabuf_dev_init(void) > +{ > + return misc_register(&udmabuf_misc); > +} > + > +static void __exit udmabuf_dev_exit(void) > +{ > + misc_deregister(&udmabuf_misc); > +} > + > +module_init(udmabuf_dev_init) > +module_exit(udmabuf_dev_exit) > + > +MODULE_AUTHOR("Gerd Hoffmann "); > +MODULE_LICENSE("GPL v2"); > diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#define TEST_PREFIX "drivers/dma-buf/udmabuf" > +#define NUM_PAGES 4 > + > +static int memfd_create(const char *name, unsigned int flags) > +{ > + return syscall(__NR_memfd_create, name, flags); > +} > + > +int main(int argc, char *argv[]) > +{ > + struct udmabuf_create create; > + int devfd, memfd, buf, ret; > + off_t size; > + void *mem; > + > + devfd = open("/dev/udmabuf", O_RDWR); > + if (devfd < 0) { > + printf("%s: [skip,no-udmabuf]\n", TEST_PREFIX); > + exit(77); > + } > + > + memfd = memfd_create("udmabuf-test", MFD_CLOEXEC); > + if (memfd < 0) { > + printf("%s: [skip,no-memfd]\n", TEST_PREFIX); > + exit(77); > + } > + > + size = getpagesize() * NUM_PAGES; > + ret = ftruncate(memfd, size); > + if (ret == -1) { > + printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX); > + exit(1); > + } > + > + memset(&create, 0, sizeof(create)); > + > + /* should fail (offset not page aligned) */ > + create.memfd = memfd; > + create.offset = getpagesize()/2; > + create.size = getpagesize(); > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-1]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (size not multiple of page) */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = getpagesize()/2; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-2]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (not memfd) */ > + create.memfd = 0; /* stdin */ > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-3]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should work */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf < 0) { > + printf("%s: [FAIL,test-4]\n", TEST_PREFIX); > + exit(1); > + } > + > + fprintf(stderr, "%s: ok\n", TEST_PREFIX); > + close(buf); > + close(memfd); > + close(devfd); > + return 0; > +} > diff --git a/MAINTAINERS b/MAINTAINERS > index a5b256b259..11a9b04277 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14934,6 +14934,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel@lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c Dupe, remove this one (since only the 2nd one has the drm-misc git repo entry). Acked-by: Daniel Vetter > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input@vger.kernel.org > @@ -15343,6 +15351,14 @@ F: arch/x86/um/ > F: fs/hostfs/ > F: fs/hppfs/ > > +USERSPACE DMA BUFFER DRIVER > +M: Gerd Hoffmann > +S: Maintained > +L: dri-devel@lists.freedesktop.org > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +T: git git://anongit.freedesktop.org/drm/drm-misc > + > USERSPACE I/O (UIO) > M: Greg Kroah-Hartman > S: Maintained > diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig > index ed3b785bae..338129eb12 100644 > --- a/drivers/dma-buf/Kconfig > +++ b/drivers/dma-buf/Kconfig > @@ -30,4 +30,12 @@ config SW_SYNC > WARNING: improper use of this can result in deadlocking kernel > drivers from userspace. Intended for test and debug only. > > +config UDMABUF > + bool "userspace dmabuf misc driver" > + default n > + depends on DMA_SHARED_BUFFER > + help > + A driver to let userspace turn memfd regions into dma-bufs. > + Qemu can use this to create host dmabufs for guest framebuffers. > + > endmenu > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile > index c33bf88631..0913a6ccab 100644 > --- a/drivers/dma-buf/Makefile > +++ b/drivers/dma-buf/Makefile > @@ -1,3 +1,4 @@ > obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o > obj-$(CONFIG_SYNC_FILE) += sync_file.o > obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o > +obj-$(CONFIG_UDMABUF) += udmabuf.o > diff --git a/tools/testing/selftests/drivers/dma-buf/Makefile b/tools/testing/selftests/drivers/dma-buf/Makefile > new file mode 100644 > index 0000000000..4154c3d7aa > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/Makefile > @@ -0,0 +1,5 @@ > +CFLAGS += -I../../../../../usr/include/ > + > +TEST_GEN_PROGS := udmabuf > + > +include ../../lib.mk > -- > 2.9.3 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch From mboxrd@z Thu Jan 1 00:00:00 1970 From: daniel at ffwll.ch (Daniel Vetter) Date: Fri, 31 Aug 2018 10:48:34 +0200 Subject: [PATCH v7] Add udmabuf misc device In-Reply-To: <20180827093444.23623-1-kraxel@redhat.com> References: <20180827093444.23623-1-kraxel@redhat.com> Message-ID: <20180831084834.GP21634@phenom.ffwll.local> On Mon, Aug 27, 2018 at 11:34:44AM +0200, Gerd Hoffmann wrote: > A driver to let userspace turn memfd regions into dma-bufs. > > Use case: Allows qemu create dmabufs for the vga framebuffer or > virtio-gpu ressources. Then they can be passed around to display > those guest things on the host. To spice client for classic full > framebuffer display, and hopefully some day to wayland server for > seamless guest window display. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 ++++++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 16 ++ > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 447 insertions(+) > create mode 100644 include/uapi/linux/udmabuf.h > create mode 100644 drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile > > diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt > index 13a7c999c0..f2ac672eb7 100644 > --- a/Documentation/ioctl/ioctl-number.txt > +++ b/Documentation/ioctl/ioctl-number.txt > @@ -272,6 +272,7 @@ Code Seq#(hex) Include File Comments > 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM > 'u' 00-1F linux/smb_fs.h gone > 'u' 20-3F linux/uvcvideo.h USB video class host driver > +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device > 'v' 00-1F linux/ext2_fs.h conflict! > 'v' 00-1F linux/fs.h conflict! > 'v' 00-0F linux/sonypi.h conflict! > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ > +#ifndef _UAPI_LINUX_UDMABUF_H > +#define _UAPI_LINUX_UDMABUF_H > + > +#include > +#include > + > +#define UDMABUF_FLAGS_CLOEXEC 0x01 > + > +struct udmabuf_create { > + __u32 memfd; > + __u32 flags; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) > + > +#endif /* _UAPI_LINUX_UDMABUF_H */ > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct udmabuf { > + u32 pagecount; > + struct page **pages; > +}; > + > +static int udmabuf_vm_fault(struct vm_fault *vmf) > +{ > + struct vm_area_struct *vma = vmf->vma; > + struct udmabuf *ubuf = vma->vm_private_data; > + > + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > + return VM_FAULT_SIGBUS; > + > + vmf->page = ubuf->pages[vmf->pgoff]; > + get_page(vmf->page); > + return 0; > +} > + > +static const struct vm_operations_struct udmabuf_vm_ops = { > + .fault = udmabuf_vm_fault, > +}; > + > +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) > +{ > + struct udmabuf *ubuf = buf->priv; > + > + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) > + return -EINVAL; > + > + vma->vm_ops = &udmabuf_vm_ops; > + vma->vm_private_data = ubuf; > + return 0; > +} > + > +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, > + enum dma_data_direction direction) > +{ > + struct udmabuf *ubuf = at->dmabuf->priv; > + struct sg_table *sg; > + > + sg = kzalloc(sizeof(*sg), GFP_KERNEL); > + if (!sg) > + goto err1; > + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, > + 0, ubuf->pagecount << PAGE_SHIFT, > + GFP_KERNEL) < 0) > + goto err2; > + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) > + goto err3; > + > + return sg; > + > +err3: > + sg_free_table(sg); > +err2: > + kfree(sg); > +err1: > + return ERR_PTR(-ENOMEM); > +} > + > +static void unmap_udmabuf(struct dma_buf_attachment *at, > + struct sg_table *sg, > + enum dma_data_direction direction) > +{ > + sg_free_table(sg); > + kfree(sg); > +} > + > +static void release_udmabuf(struct dma_buf *buf) > +{ > + struct udmabuf *ubuf = buf->priv; > + pgoff_t pg; > + > + for (pg = 0; pg < ubuf->pagecount; pg++) > + put_page(ubuf->pages[pg]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) > +{ > + struct udmabuf *ubuf = buf->priv; > + struct page *page = ubuf->pages[page_num]; > + > + return kmap(page); > +} > + > +static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; > + > + exp_info.ops = &udmabuf_ops; > + exp_info.size = ubuf->pagecount << PAGE_SHIFT; > + exp_info.priv = ubuf; > + > + buf = dma_buf_export(&exp_info); > + if (IS_ERR(buf)) { > + ret = PTR_ERR(buf); > + goto err_put_pages; > + } > + > + flags = 0; > + if (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + return ret; > +} > + > +static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, > + unsigned long arg) > +{ > + long ret; > + > + switch (ioctl) { > + case UDMABUF_CREATE: > + ret = udmabuf_ioctl_create(filp, arg); > + break; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(filp, arg); > + break; > + default: > + ret = -EINVAL; > + break; > + } > + return ret; > +} > + > +static const struct file_operations udmabuf_fops = { > + .owner = THIS_MODULE, > + .unlocked_ioctl = udmabuf_ioctl, > +}; > + > +static struct miscdevice udmabuf_misc = { > + .minor = MISC_DYNAMIC_MINOR, > + .name = "udmabuf", > + .fops = &udmabuf_fops, > +}; > + > +static int __init udmabuf_dev_init(void) > +{ > + return misc_register(&udmabuf_misc); > +} > + > +static void __exit udmabuf_dev_exit(void) > +{ > + misc_deregister(&udmabuf_misc); > +} > + > +module_init(udmabuf_dev_init) > +module_exit(udmabuf_dev_exit) > + > +MODULE_AUTHOR("Gerd Hoffmann "); > +MODULE_LICENSE("GPL v2"); > diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#define TEST_PREFIX "drivers/dma-buf/udmabuf" > +#define NUM_PAGES 4 > + > +static int memfd_create(const char *name, unsigned int flags) > +{ > + return syscall(__NR_memfd_create, name, flags); > +} > + > +int main(int argc, char *argv[]) > +{ > + struct udmabuf_create create; > + int devfd, memfd, buf, ret; > + off_t size; > + void *mem; > + > + devfd = open("/dev/udmabuf", O_RDWR); > + if (devfd < 0) { > + printf("%s: [skip,no-udmabuf]\n", TEST_PREFIX); > + exit(77); > + } > + > + memfd = memfd_create("udmabuf-test", MFD_CLOEXEC); > + if (memfd < 0) { > + printf("%s: [skip,no-memfd]\n", TEST_PREFIX); > + exit(77); > + } > + > + size = getpagesize() * NUM_PAGES; > + ret = ftruncate(memfd, size); > + if (ret == -1) { > + printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX); > + exit(1); > + } > + > + memset(&create, 0, sizeof(create)); > + > + /* should fail (offset not page aligned) */ > + create.memfd = memfd; > + create.offset = getpagesize()/2; > + create.size = getpagesize(); > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-1]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (size not multiple of page) */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = getpagesize()/2; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-2]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (not memfd) */ > + create.memfd = 0; /* stdin */ > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-3]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should work */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf < 0) { > + printf("%s: [FAIL,test-4]\n", TEST_PREFIX); > + exit(1); > + } > + > + fprintf(stderr, "%s: ok\n", TEST_PREFIX); > + close(buf); > + close(memfd); > + close(devfd); > + return 0; > +} > diff --git a/MAINTAINERS b/MAINTAINERS > index a5b256b259..11a9b04277 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14934,6 +14934,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel at lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c Dupe, remove this one (since only the 2nd one has the drm-misc git repo entry). Acked-by: Daniel Vetter > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input at vger.kernel.org > @@ -15343,6 +15351,14 @@ F: arch/x86/um/ > F: fs/hostfs/ > F: fs/hppfs/ > > +USERSPACE DMA BUFFER DRIVER > +M: Gerd Hoffmann > +S: Maintained > +L: dri-devel at lists.freedesktop.org > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +T: git git://anongit.freedesktop.org/drm/drm-misc > + > USERSPACE I/O (UIO) > M: Greg Kroah-Hartman > S: Maintained > diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig > index ed3b785bae..338129eb12 100644 > --- a/drivers/dma-buf/Kconfig > +++ b/drivers/dma-buf/Kconfig > @@ -30,4 +30,12 @@ config SW_SYNC > WARNING: improper use of this can result in deadlocking kernel > drivers from userspace. Intended for test and debug only. > > +config UDMABUF > + bool "userspace dmabuf misc driver" > + default n > + depends on DMA_SHARED_BUFFER > + help > + A driver to let userspace turn memfd regions into dma-bufs. > + Qemu can use this to create host dmabufs for guest framebuffers. > + > endmenu > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile > index c33bf88631..0913a6ccab 100644 > --- a/drivers/dma-buf/Makefile > +++ b/drivers/dma-buf/Makefile > @@ -1,3 +1,4 @@ > obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o > obj-$(CONFIG_SYNC_FILE) += sync_file.o > obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o > +obj-$(CONFIG_UDMABUF) += udmabuf.o > diff --git a/tools/testing/selftests/drivers/dma-buf/Makefile b/tools/testing/selftests/drivers/dma-buf/Makefile > new file mode 100644 > index 0000000000..4154c3d7aa > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/Makefile > @@ -0,0 +1,5 @@ > +CFLAGS += -I../../../../../usr/include/ > + > +TEST_GEN_PROGS := udmabuf > + > +include ../../lib.mk > -- > 2.9.3 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch From mboxrd@z Thu Jan 1 00:00:00 1970 From: daniel@ffwll.ch (Daniel Vetter) Date: Fri, 31 Aug 2018 10:48:34 +0200 Subject: [PATCH v7] Add udmabuf misc device In-Reply-To: <20180827093444.23623-1-kraxel@redhat.com> References: <20180827093444.23623-1-kraxel@redhat.com> Message-ID: <20180831084834.GP21634@phenom.ffwll.local> Content-Type: text/plain; charset="UTF-8" Message-ID: <20180831084834._AnfI41Bk7sBkKeWg6AHAZ9TLu5397Da_wQElB7U3ik@z> On Mon, Aug 27, 2018@11:34:44AM +0200, Gerd Hoffmann wrote: > A driver to let userspace turn memfd regions into dma-bufs. > > Use case: Allows qemu create dmabufs for the vga framebuffer or > virtio-gpu ressources. Then they can be passed around to display > those guest things on the host. To spice client for classic full > framebuffer display, and hopefully some day to wayland server for > seamless guest window display. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 ++++++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 16 ++ > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 447 insertions(+) > create mode 100644 include/uapi/linux/udmabuf.h > create mode 100644 drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile > > diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt > index 13a7c999c0..f2ac672eb7 100644 > --- a/Documentation/ioctl/ioctl-number.txt > +++ b/Documentation/ioctl/ioctl-number.txt > @@ -272,6 +272,7 @@ Code Seq#(hex) Include File Comments > 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM > 'u' 00-1F linux/smb_fs.h gone > 'u' 20-3F linux/uvcvideo.h USB video class host driver > +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device > 'v' 00-1F linux/ext2_fs.h conflict! > 'v' 00-1F linux/fs.h conflict! > 'v' 00-0F linux/sonypi.h conflict! > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ > +#ifndef _UAPI_LINUX_UDMABUF_H > +#define _UAPI_LINUX_UDMABUF_H > + > +#include > +#include > + > +#define UDMABUF_FLAGS_CLOEXEC 0x01 > + > +struct udmabuf_create { > + __u32 memfd; > + __u32 flags; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) > + > +#endif /* _UAPI_LINUX_UDMABUF_H */ > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct udmabuf { > + u32 pagecount; > + struct page **pages; > +}; > + > +static int udmabuf_vm_fault(struct vm_fault *vmf) > +{ > + struct vm_area_struct *vma = vmf->vma; > + struct udmabuf *ubuf = vma->vm_private_data; > + > + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > + return VM_FAULT_SIGBUS; > + > + vmf->page = ubuf->pages[vmf->pgoff]; > + get_page(vmf->page); > + return 0; > +} > + > +static const struct vm_operations_struct udmabuf_vm_ops = { > + .fault = udmabuf_vm_fault, > +}; > + > +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) > +{ > + struct udmabuf *ubuf = buf->priv; > + > + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) > + return -EINVAL; > + > + vma->vm_ops = &udmabuf_vm_ops; > + vma->vm_private_data = ubuf; > + return 0; > +} > + > +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, > + enum dma_data_direction direction) > +{ > + struct udmabuf *ubuf = at->dmabuf->priv; > + struct sg_table *sg; > + > + sg = kzalloc(sizeof(*sg), GFP_KERNEL); > + if (!sg) > + goto err1; > + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, > + 0, ubuf->pagecount << PAGE_SHIFT, > + GFP_KERNEL) < 0) > + goto err2; > + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) > + goto err3; > + > + return sg; > + > +err3: > + sg_free_table(sg); > +err2: > + kfree(sg); > +err1: > + return ERR_PTR(-ENOMEM); > +} > + > +static void unmap_udmabuf(struct dma_buf_attachment *at, > + struct sg_table *sg, > + enum dma_data_direction direction) > +{ > + sg_free_table(sg); > + kfree(sg); > +} > + > +static void release_udmabuf(struct dma_buf *buf) > +{ > + struct udmabuf *ubuf = buf->priv; > + pgoff_t pg; > + > + for (pg = 0; pg < ubuf->pagecount; pg++) > + put_page(ubuf->pages[pg]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) > +{ > + struct udmabuf *ubuf = buf->priv; > + struct page *page = ubuf->pages[page_num]; > + > + return kmap(page); > +} > + > +static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; > + > + exp_info.ops = &udmabuf_ops; > + exp_info.size = ubuf->pagecount << PAGE_SHIFT; > + exp_info.priv = ubuf; > + > + buf = dma_buf_export(&exp_info); > + if (IS_ERR(buf)) { > + ret = PTR_ERR(buf); > + goto err_put_pages; > + } > + > + flags = 0; > + if (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + return ret; > +} > + > +static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, > + unsigned long arg) > +{ > + long ret; > + > + switch (ioctl) { > + case UDMABUF_CREATE: > + ret = udmabuf_ioctl_create(filp, arg); > + break; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(filp, arg); > + break; > + default: > + ret = -EINVAL; > + break; > + } > + return ret; > +} > + > +static const struct file_operations udmabuf_fops = { > + .owner = THIS_MODULE, > + .unlocked_ioctl = udmabuf_ioctl, > +}; > + > +static struct miscdevice udmabuf_misc = { > + .minor = MISC_DYNAMIC_MINOR, > + .name = "udmabuf", > + .fops = &udmabuf_fops, > +}; > + > +static int __init udmabuf_dev_init(void) > +{ > + return misc_register(&udmabuf_misc); > +} > + > +static void __exit udmabuf_dev_exit(void) > +{ > + misc_deregister(&udmabuf_misc); > +} > + > +module_init(udmabuf_dev_init) > +module_exit(udmabuf_dev_exit) > + > +MODULE_AUTHOR("Gerd Hoffmann "); > +MODULE_LICENSE("GPL v2"); > diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#define TEST_PREFIX "drivers/dma-buf/udmabuf" > +#define NUM_PAGES 4 > + > +static int memfd_create(const char *name, unsigned int flags) > +{ > + return syscall(__NR_memfd_create, name, flags); > +} > + > +int main(int argc, char *argv[]) > +{ > + struct udmabuf_create create; > + int devfd, memfd, buf, ret; > + off_t size; > + void *mem; > + > + devfd = open("/dev/udmabuf", O_RDWR); > + if (devfd < 0) { > + printf("%s: [skip,no-udmabuf]\n", TEST_PREFIX); > + exit(77); > + } > + > + memfd = memfd_create("udmabuf-test", MFD_CLOEXEC); > + if (memfd < 0) { > + printf("%s: [skip,no-memfd]\n", TEST_PREFIX); > + exit(77); > + } > + > + size = getpagesize() * NUM_PAGES; > + ret = ftruncate(memfd, size); > + if (ret == -1) { > + printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX); > + exit(1); > + } > + > + memset(&create, 0, sizeof(create)); > + > + /* should fail (offset not page aligned) */ > + create.memfd = memfd; > + create.offset = getpagesize()/2; > + create.size = getpagesize(); > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-1]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (size not multiple of page) */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = getpagesize()/2; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-2]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (not memfd) */ > + create.memfd = 0; /* stdin */ > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-3]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should work */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf < 0) { > + printf("%s: [FAIL,test-4]\n", TEST_PREFIX); > + exit(1); > + } > + > + fprintf(stderr, "%s: ok\n", TEST_PREFIX); > + close(buf); > + close(memfd); > + close(devfd); > + return 0; > +} > diff --git a/MAINTAINERS b/MAINTAINERS > index a5b256b259..11a9b04277 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14934,6 +14934,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel at lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c Dupe, remove this one (since only the 2nd one has the drm-misc git repo entry). Acked-by: Daniel Vetter > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input at vger.kernel.org > @@ -15343,6 +15351,14 @@ F: arch/x86/um/ > F: fs/hostfs/ > F: fs/hppfs/ > > +USERSPACE DMA BUFFER DRIVER > +M: Gerd Hoffmann > +S: Maintained > +L: dri-devel at lists.freedesktop.org > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +T: git git://anongit.freedesktop.org/drm/drm-misc > + > USERSPACE I/O (UIO) > M: Greg Kroah-Hartman > S: Maintained > diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig > index ed3b785bae..338129eb12 100644 > --- a/drivers/dma-buf/Kconfig > +++ b/drivers/dma-buf/Kconfig > @@ -30,4 +30,12 @@ config SW_SYNC > WARNING: improper use of this can result in deadlocking kernel > drivers from userspace. Intended for test and debug only. > > +config UDMABUF > + bool "userspace dmabuf misc driver" > + default n > + depends on DMA_SHARED_BUFFER > + help > + A driver to let userspace turn memfd regions into dma-bufs. > + Qemu can use this to create host dmabufs for guest framebuffers. > + > endmenu > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile > index c33bf88631..0913a6ccab 100644 > --- a/drivers/dma-buf/Makefile > +++ b/drivers/dma-buf/Makefile > @@ -1,3 +1,4 @@ > obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o > obj-$(CONFIG_SYNC_FILE) += sync_file.o > obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o > +obj-$(CONFIG_UDMABUF) += udmabuf.o > diff --git a/tools/testing/selftests/drivers/dma-buf/Makefile b/tools/testing/selftests/drivers/dma-buf/Makefile > new file mode 100644 > index 0000000000..4154c3d7aa > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/Makefile > @@ -0,0 +1,5 @@ > +CFLAGS += -I../../../../../usr/include/ > + > +TEST_GEN_PROGS := udmabuf > + > +include ../../lib.mk > -- > 2.9.3 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch From mboxrd@z Thu Jan 1 00:00:00 1970 From: Daniel Vetter Subject: Re: [PATCH v7] Add udmabuf misc device Date: Fri, 31 Aug 2018 10:48:34 +0200 Message-ID: <20180831084834.GP21634@phenom.ffwll.local> References: <20180827093444.23623-1-kraxel@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from mail-ed1-x542.google.com (mail-ed1-x542.google.com [IPv6:2a00:1450:4864:20::542]) by gabe.freedesktop.org (Postfix) with ESMTPS id B89496E859 for ; Fri, 31 Aug 2018 08:48:39 +0000 (UTC) Received: by mail-ed1-x542.google.com with SMTP id h4-v6so8486727edi.6 for ; Fri, 31 Aug 2018 01:48:39 -0700 (PDT) Content-Disposition: inline In-Reply-To: <20180827093444.23623-1-kraxel@redhat.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Gerd Hoffmann Cc: "open list:KERNEL SELFTEST FRAMEWORK" , Tomeu Vizoso , Jonathan Corbet , David Airlie , "open list:DOCUMENTATION" , open list , dri-devel@lists.freedesktop.org, "moderated list:DMA BUFFER SHARING FRAMEWORK" , Laurent Pinchart , Shuah Khan , "open list:DMA BUFFER SHARING FRAMEWORK" List-Id: dri-devel@lists.freedesktop.org T24gTW9uLCBBdWcgMjcsIDIwMTggYXQgMTE6MzQ6NDRBTSArMDIwMCwgR2VyZCBIb2ZmbWFubiB3 cm90ZToKPiBBIGRyaXZlciB0byBsZXQgdXNlcnNwYWNlIHR1cm4gbWVtZmQgcmVnaW9ucyBpbnRv IGRtYS1idWZzLgo+IAo+IFVzZSBjYXNlOiAgQWxsb3dzIHFlbXUgY3JlYXRlIGRtYWJ1ZnMgZm9y IHRoZSB2Z2EgZnJhbWVidWZmZXIgb3IKPiB2aXJ0aW8tZ3B1IHJlc3NvdXJjZXMuICBUaGVuIHRo ZXkgY2FuIGJlIHBhc3NlZCBhcm91bmQgdG8gZGlzcGxheQo+IHRob3NlIGd1ZXN0IHRoaW5ncyBv biB0aGUgaG9zdC4gIFRvIHNwaWNlIGNsaWVudCBmb3IgY2xhc3NpYyBmdWxsCj4gZnJhbWVidWZm ZXIgZGlzcGxheSwgYW5kIGhvcGVmdWxseSBzb21lIGRheSB0byB3YXlsYW5kIHNlcnZlciBmb3IK PiBzZWFtbGVzcyBndWVzdCB3aW5kb3cgZGlzcGxheS4KPiAKPiBxZW11IHRlc3QgYnJhbmNoOgo+ ICAgaHR0cHM6Ly9naXQua3JheGVsLm9yZy9jZ2l0L3FlbXUvbG9nLz9oPXNpcml1cy91ZG1hYnVm Cj4gCj4gQ2M6IERhdmlkIEFpcmxpZSA8YWlybGllZEBsaW51eC5pZT4KPiBDYzogVG9tZXUgVml6 b3NvIDx0b21ldS52aXpvc29AY29sbGFib3JhLmNvbT4KPiBDYzogTGF1cmVudCBQaW5jaGFydCA8 bGF1cmVudC5waW5jaGFydEBpZGVhc29uYm9hcmQuY29tPgo+IENjOiBEYW5pZWwgVmV0dGVyIDxk YW5pZWxAZmZ3bGwuY2g+Cj4gU2lnbmVkLW9mZi1ieTogR2VyZCBIb2ZmbWFubiA8a3JheGVsQHJl ZGhhdC5jb20+Cj4gLS0tCj4gIERvY3VtZW50YXRpb24vaW9jdGwvaW9jdGwtbnVtYmVyLnR4dCAg ICAgICAgICAgICAgfCAgIDEgKwo+ICBpbmNsdWRlL3VhcGkvbGludXgvdWRtYWJ1Zi5oICAgICAg ICAgICAgICAgICAgICAgIHwgIDMzICsrKwo+ICBkcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jICAg ICAgICAgICAgICAgICAgICAgICAgIHwgMjg3ICsrKysrKysrKysrKysrKysrKysrKysKPiAgdG9v bHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9kbWEtYnVmL3VkbWFidWYuYyB8ICA5NiArKysr KysrKwo+ICBNQUlOVEFJTkVSUyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg IHwgIDE2ICsrCj4gIGRyaXZlcnMvZG1hLWJ1Zi9LY29uZmlnICAgICAgICAgICAgICAgICAgICAg ICAgICAgfCAgIDggKwo+ICBkcml2ZXJzL2RtYS1idWYvTWFrZWZpbGUgICAgICAgICAgICAgICAg ICAgICAgICAgIHwgICAxICsKPiAgdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9kbWEt YnVmL01ha2VmaWxlICB8ICAgNSArCj4gIDggZmlsZXMgY2hhbmdlZCwgNDQ3IGluc2VydGlvbnMo KykKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGluY2x1ZGUvdWFwaS9saW51eC91ZG1hYnVmLmgKPiAg Y3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMKPiAgY3JlYXRlIG1v ZGUgMTAwNjQ0IHRvb2xzL3Rlc3Rpbmcvc2VsZnRlc3RzL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVm LmMKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IHRvb2xzL3Rlc3Rpbmcvc2VsZnRlc3RzL2RyaXZlcnMv ZG1hLWJ1Zi9NYWtlZmlsZQo+IAo+IGRpZmYgLS1naXQgYS9Eb2N1bWVudGF0aW9uL2lvY3RsL2lv Y3RsLW51bWJlci50eHQgYi9Eb2N1bWVudGF0aW9uL2lvY3RsL2lvY3RsLW51bWJlci50eHQKPiBp bmRleCAxM2E3Yzk5OWMwLi5mMmFjNjcyZWI3IDEwMDY0NAo+IC0tLSBhL0RvY3VtZW50YXRpb24v aW9jdGwvaW9jdGwtbnVtYmVyLnR4dAo+ICsrKyBiL0RvY3VtZW50YXRpb24vaW9jdGwvaW9jdGwt bnVtYmVyLnR4dAo+IEBAIC0yNzIsNiArMjcyLDcgQEAgQ29kZSAgU2VxIyhoZXgpCUluY2x1ZGUg RmlsZQkJQ29tbWVudHMKPiAgJ3QnCTkwLTkxCWxpbnV4L3Rvc2hpYmEuaAkJdG9zaGliYSBhbmQg dG9zaGliYV9hY3BpIFNNTQo+ICAndScJMDAtMUYJbGludXgvc21iX2ZzLmgJCWdvbmUKPiAgJ3Un CTIwLTNGCWxpbnV4L3V2Y3ZpZGVvLmgJVVNCIHZpZGVvIGNsYXNzIGhvc3QgZHJpdmVyCj4gKyd1 Jwk0MC00ZglsaW51eC91ZG1hYnVmLmgJCXVzZXJzcGFjZSBkbWEtYnVmIG1pc2MgZGV2aWNlCj4g ICd2JwkwMC0xRglsaW51eC9leHQyX2ZzLmgJCWNvbmZsaWN0IQo+ICAndicJMDAtMUYJbGludXgv ZnMuaAkJY29uZmxpY3QhCj4gICd2JwkwMC0wRglsaW51eC9zb255cGkuaAkJY29uZmxpY3QhCj4g ZGlmZiAtLWdpdCBhL2luY2x1ZGUvdWFwaS9saW51eC91ZG1hYnVmLmggYi9pbmNsdWRlL3VhcGkv bGludXgvdWRtYWJ1Zi5oCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwMDAw Li40NmI2NTMyZWQ4Cj4gLS0tIC9kZXYvbnVsbAo+ICsrKyBiL2luY2x1ZGUvdWFwaS9saW51eC91 ZG1hYnVmLmgKPiBAQCAtMCwwICsxLDMzIEBACj4gKy8qIFNQRFgtTGljZW5zZS1JZGVudGlmaWVy OiBHUEwtMi4wIFdJVEggTGludXgtc3lzY2FsbC1ub3RlICovCj4gKyNpZm5kZWYgX1VBUElfTElO VVhfVURNQUJVRl9ICj4gKyNkZWZpbmUgX1VBUElfTElOVVhfVURNQUJVRl9ICj4gKwo+ICsjaW5j bHVkZSA8bGludXgvdHlwZXMuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2lvY3RsLmg+Cj4gKwo+ICsj ZGVmaW5lIFVETUFCVUZfRkxBR1NfQ0xPRVhFQwkweDAxCj4gKwo+ICtzdHJ1Y3QgdWRtYWJ1Zl9j cmVhdGUgewo+ICsJX191MzIgbWVtZmQ7Cj4gKwlfX3UzMiBmbGFnczsKPiArCV9fdTY0IG9mZnNl dDsKPiArCV9fdTY0IHNpemU7Cj4gK307Cj4gKwo+ICtzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGVfaXRl bSB7Cj4gKwlfX3UzMiBtZW1mZDsKPiArCV9fdTMyIF9fcGFkOwo+ICsJX191NjQgb2Zmc2V0Owo+ ICsJX191NjQgc2l6ZTsKPiArfTsKPiArCj4gK3N0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9saXN0IHsK PiArCV9fdTMyIGZsYWdzOwo+ICsJX191MzIgY291bnQ7Cj4gKwlzdHJ1Y3QgdWRtYWJ1Zl9jcmVh dGVfaXRlbSBsaXN0W107Cj4gK307Cj4gKwo+ICsjZGVmaW5lIFVETUFCVUZfQ1JFQVRFICAgICAg IF9JT1coJ3UnLCAweDQyLCBzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGUpCj4gKyNkZWZpbmUgVURNQUJV Rl9DUkVBVEVfTElTVCAgX0lPVygndScsIDB4NDMsIHN0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9saXN0 KQo+ICsKPiArI2VuZGlmIC8qIF9VQVBJX0xJTlVYX1VETUFCVUZfSCAqLwo+IGRpZmYgLS1naXQg YS9kcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jIGIvZHJpdmVycy9kbWEtYnVmL3VkbWFidWYuYwo+ IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMDAwMC4uOGUyNDIwNDUyNgo+IC0t LSAvZGV2L251bGwKPiArKysgYi9kcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCj4gQEAgLTAsMCAr MSwyODcgQEAKPiArLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKPiArI2luY2x1 ZGUgPGxpbnV4L2luaXQuaD4KPiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgo+ICsjaW5jbHVk ZSA8bGludXgvZGV2aWNlLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4KPiArI2luY2x1 ZGUgPGxpbnV4L3NsYWIuaD4KPiArI2luY2x1ZGUgPGxpbnV4L21pc2NkZXZpY2UuaD4KPiArI2lu Y2x1ZGUgPGxpbnV4L2RtYS1idWYuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2hpZ2htZW0uaD4KPiAr I2luY2x1ZGUgPGxpbnV4L2NyZWQuaD4KPiArI2luY2x1ZGUgPGxpbnV4L3NobWVtX2ZzLmg+Cj4g KyNpbmNsdWRlIDxsaW51eC9tZW1mZC5oPgo+ICsKPiArI2luY2x1ZGUgPHVhcGkvbGludXgvdWRt YWJ1Zi5oPgo+ICsKPiArc3RydWN0IHVkbWFidWYgewo+ICsJdTMyIHBhZ2Vjb3VudDsKPiArCXN0 cnVjdCBwYWdlICoqcGFnZXM7Cj4gK307Cj4gKwo+ICtzdGF0aWMgaW50IHVkbWFidWZfdm1fZmF1 bHQoc3RydWN0IHZtX2ZhdWx0ICp2bWYpCj4gK3sKPiArCXN0cnVjdCB2bV9hcmVhX3N0cnVjdCAq dm1hID0gdm1mLT52bWE7Cj4gKwlzdHJ1Y3QgdWRtYWJ1ZiAqdWJ1ZiA9IHZtYS0+dm1fcHJpdmF0 ZV9kYXRhOwo+ICsKPiArCWlmIChXQVJOX09OKHZtZi0+cGdvZmYgPj0gdWJ1Zi0+cGFnZWNvdW50 KSkKPiArCQlyZXR1cm4gVk1fRkFVTFRfU0lHQlVTOwo+ICsKPiArCXZtZi0+cGFnZSA9IHVidWYt PnBhZ2VzW3ZtZi0+cGdvZmZdOwo+ICsJZ2V0X3BhZ2Uodm1mLT5wYWdlKTsKPiArCXJldHVybiAw Owo+ICt9Cj4gKwo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IHZtX29wZXJhdGlvbnNfc3RydWN0IHVk bWFidWZfdm1fb3BzID0gewo+ICsJLmZhdWx0ID0gdWRtYWJ1Zl92bV9mYXVsdCwKPiArfTsKPiAr Cj4gK3N0YXRpYyBpbnQgbW1hcF91ZG1hYnVmKHN0cnVjdCBkbWFfYnVmICpidWYsIHN0cnVjdCB2 bV9hcmVhX3N0cnVjdCAqdm1hKQo+ICt7Cj4gKwlzdHJ1Y3QgdWRtYWJ1ZiAqdWJ1ZiA9IGJ1Zi0+ cHJpdjsKPiArCj4gKwlpZiAoKHZtYS0+dm1fZmxhZ3MgJiAoVk1fU0hBUkVEIHwgVk1fTUFZU0hB UkUpKSA9PSAwKQo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsKPiArCXZtYS0+dm1fb3BzID0gJnVk bWFidWZfdm1fb3BzOwo+ICsJdm1hLT52bV9wcml2YXRlX2RhdGEgPSB1YnVmOwo+ICsJcmV0dXJu IDA7Cj4gK30KPiArCj4gK3N0YXRpYyBzdHJ1Y3Qgc2dfdGFibGUgKm1hcF91ZG1hYnVmKHN0cnVj dCBkbWFfYnVmX2F0dGFjaG1lbnQgKmF0LAo+ICsJCQkJICAgIGVudW0gZG1hX2RhdGFfZGlyZWN0 aW9uIGRpcmVjdGlvbikKPiArewo+ICsJc3RydWN0IHVkbWFidWYgKnVidWYgPSBhdC0+ZG1hYnVm LT5wcml2Owo+ICsJc3RydWN0IHNnX3RhYmxlICpzZzsKPiArCj4gKwlzZyA9IGt6YWxsb2Moc2l6 ZW9mKCpzZyksIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFzZykKPiArCQlnb3RvIGVycjE7Cj4gKwlp ZiAoc2dfYWxsb2NfdGFibGVfZnJvbV9wYWdlcyhzZywgdWJ1Zi0+cGFnZXMsIHVidWYtPnBhZ2Vj b3VudCwKPiArCQkJCSAgICAgIDAsIHVidWYtPnBhZ2Vjb3VudCA8PCBQQUdFX1NISUZULAo+ICsJ CQkJICAgICAgR0ZQX0tFUk5FTCkgPCAwKQo+ICsJCWdvdG8gZXJyMjsKPiArCWlmICghZG1hX21h cF9zZyhhdC0+ZGV2LCBzZy0+c2dsLCBzZy0+bmVudHMsIGRpcmVjdGlvbikpCj4gKwkJZ290byBl cnIzOwo+ICsKPiArCXJldHVybiBzZzsKPiArCj4gK2VycjM6Cj4gKwlzZ19mcmVlX3RhYmxlKHNn KTsKPiArZXJyMjoKPiArCWtmcmVlKHNnKTsKPiArZXJyMToKPiArCXJldHVybiBFUlJfUFRSKC1F Tk9NRU0pOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCB1bm1hcF91ZG1hYnVmKHN0cnVjdCBkbWFf YnVmX2F0dGFjaG1lbnQgKmF0LAo+ICsJCQkgIHN0cnVjdCBzZ190YWJsZSAqc2csCj4gKwkJCSAg ZW51bSBkbWFfZGF0YV9kaXJlY3Rpb24gZGlyZWN0aW9uKQo+ICt7Cj4gKwlzZ19mcmVlX3RhYmxl KHNnKTsKPiArCWtmcmVlKHNnKTsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgcmVsZWFzZV91ZG1h YnVmKHN0cnVjdCBkbWFfYnVmICpidWYpCj4gK3sKPiArCXN0cnVjdCB1ZG1hYnVmICp1YnVmID0g YnVmLT5wcml2Owo+ICsJcGdvZmZfdCBwZzsKPiArCj4gKwlmb3IgKHBnID0gMDsgcGcgPCB1YnVm LT5wYWdlY291bnQ7IHBnKyspCj4gKwkJcHV0X3BhZ2UodWJ1Zi0+cGFnZXNbcGddKTsKPiArCWtm cmVlKHVidWYtPnBhZ2VzKTsKPiArCWtmcmVlKHVidWYpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9p ZCAqa21hcF91ZG1hYnVmKHN0cnVjdCBkbWFfYnVmICpidWYsIHVuc2lnbmVkIGxvbmcgcGFnZV9u dW0pCj4gK3sKPiArCXN0cnVjdCB1ZG1hYnVmICp1YnVmID0gYnVmLT5wcml2Owo+ICsJc3RydWN0 IHBhZ2UgKnBhZ2UgPSB1YnVmLT5wYWdlc1twYWdlX251bV07Cj4gKwo+ICsJcmV0dXJuIGttYXAo cGFnZSk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGt1bm1hcF91ZG1hYnVmKHN0cnVjdCBkbWFf YnVmICpidWYsIHVuc2lnbmVkIGxvbmcgcGFnZV9udW0sCj4gKwkJCSAgIHZvaWQgKnZhZGRyKQo+ ICt7Cj4gKwlrdW5tYXAodmFkZHIpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgc3RydWN0IGRtYV9idWZf b3BzIHVkbWFidWZfb3BzID0gewo+ICsJLm1hcF9kbWFfYnVmCSAgPSBtYXBfdWRtYWJ1ZiwKPiAr CS51bm1hcF9kbWFfYnVmCSAgPSB1bm1hcF91ZG1hYnVmLAo+ICsJLnJlbGVhc2UJICA9IHJlbGVh c2VfdWRtYWJ1ZiwKPiArCS5tYXAJCSAgPSBrbWFwX3VkbWFidWYsCj4gKwkudW5tYXAJCSAgPSBr dW5tYXBfdWRtYWJ1ZiwKPiArCS5tbWFwCQkgID0gbW1hcF91ZG1hYnVmLAo+ICt9Owo+ICsKPiAr I2RlZmluZSBTRUFMU19XQU5URUQgKEZfU0VBTF9TSFJJTkspCj4gKyNkZWZpbmUgU0VBTFNfREVO SUVEIChGX1NFQUxfV1JJVEUpCj4gKwo+ICtzdGF0aWMgbG9uZyB1ZG1hYnVmX2NyZWF0ZShzdHJ1 Y3QgdWRtYWJ1Zl9jcmVhdGVfbGlzdCAqaGVhZCwKPiArCQkJICAgc3RydWN0IHVkbWFidWZfY3Jl YXRlX2l0ZW0gKmxpc3QpCj4gK3sKPiArCURFRklORV9ETUFfQlVGX0VYUE9SVF9JTkZPKGV4cF9p bmZvKTsKPiArCXN0cnVjdCBmaWxlICptZW1mZCA9IE5VTEw7Cj4gKwlzdHJ1Y3QgdWRtYWJ1ZiAq dWJ1ZjsKPiArCXN0cnVjdCBkbWFfYnVmICpidWY7Cj4gKwlwZ29mZl90IHBnb2ZmLCBwZ2NudCwg cGdpZHgsIHBnYnVmOwo+ICsJc3RydWN0IHBhZ2UgKnBhZ2U7Cj4gKwlpbnQgc2VhbHMsIHJldCA9 IC1FSU5WQUw7Cj4gKwl1MzIgaSwgZmxhZ3M7Cj4gKwo+ICsJdWJ1ZiA9IGt6YWxsb2Moc2l6ZW9m KHN0cnVjdCB1ZG1hYnVmKSwgR0ZQX0tFUk5FTCk7Cj4gKwlpZiAoIXVidWYpCj4gKwkJcmV0dXJu IC1FTk9NRU07Cj4gKwo+ICsJZm9yIChpID0gMDsgaSA8IGhlYWQtPmNvdW50OyBpKyspIHsKPiAr CQlpZiAoIUlTX0FMSUdORUQobGlzdFtpXS5vZmZzZXQsIFBBR0VfU0laRSkpCj4gKwkJCWdvdG8g ZXJyX2ZyZWVfdWJ1ZjsKPiArCQlpZiAoIUlTX0FMSUdORUQobGlzdFtpXS5zaXplLCBQQUdFX1NJ WkUpKQo+ICsJCQlnb3RvIGVycl9mcmVlX3VidWY7Cj4gKwkJdWJ1Zi0+cGFnZWNvdW50ICs9IGxp c3RbaV0uc2l6ZSA+PiBQQUdFX1NISUZUOwo+ICsJfQo+ICsJdWJ1Zi0+cGFnZXMgPSBrbWFsbG9j X2FycmF5KHVidWYtPnBhZ2Vjb3VudCwgc2l6ZW9mKHN0cnVjdCBwYWdlICopLAo+ICsJCQkJICAg IEdGUF9LRVJORUwpOwo+ICsJaWYgKCF1YnVmLT5wYWdlcykgewo+ICsJCXJldCA9IC1FTk9NRU07 Cj4gKwkJZ290byBlcnJfZnJlZV91YnVmOwo+ICsJfQo+ICsKPiArCXBnYnVmID0gMDsKPiArCWZv ciAoaSA9IDA7IGkgPCBoZWFkLT5jb3VudDsgaSsrKSB7Cj4gKwkJbWVtZmQgPSBmZ2V0KGxpc3Rb aV0ubWVtZmQpOwo+ICsJCWlmICghbWVtZmQpCj4gKwkJCWdvdG8gZXJyX3B1dF9wYWdlczsKPiAr CQlpZiAoIXNobWVtX21hcHBpbmcoZmlsZV9pbm9kZShtZW1mZCktPmlfbWFwcGluZykpCj4gKwkJ CWdvdG8gZXJyX3B1dF9wYWdlczsKPiArCQlzZWFscyA9IG1lbWZkX2ZjbnRsKG1lbWZkLCBGX0dF VF9TRUFMUywgMCk7Cj4gKwkJaWYgKHNlYWxzID09IC1FSU5WQUwgfHwKPiArCQkgICAgKHNlYWxz ICYgU0VBTFNfV0FOVEVEKSAhPSBTRUFMU19XQU5URUQgfHwKPiArCQkgICAgKHNlYWxzICYgU0VB TFNfREVOSUVEKSAhPSAwKQo+ICsJCQlnb3RvIGVycl9wdXRfcGFnZXM7Cj4gKwkJcGdvZmYgPSBs aXN0W2ldLm9mZnNldCA+PiBQQUdFX1NISUZUOwo+ICsJCXBnY250ID0gbGlzdFtpXS5zaXplICAg Pj4gUEFHRV9TSElGVDsKPiArCQlmb3IgKHBnaWR4ID0gMDsgcGdpZHggPCBwZ2NudDsgcGdpZHgr Kykgewo+ICsJCQlwYWdlID0gc2htZW1fcmVhZF9tYXBwaW5nX3BhZ2UoCj4gKwkJCQlmaWxlX2lu b2RlKG1lbWZkKS0+aV9tYXBwaW5nLCBwZ29mZiArIHBnaWR4KTsKPiArCQkJaWYgKElTX0VSUihw YWdlKSkgewo+ICsJCQkJcmV0ID0gUFRSX0VSUihwYWdlKTsKPiArCQkJCWdvdG8gZXJyX3B1dF9w YWdlczsKPiArCQkJfQo+ICsJCQl1YnVmLT5wYWdlc1twZ2J1ZisrXSA9IHBhZ2U7Cj4gKwkJfQo+ ICsJCWZwdXQobWVtZmQpOwo+ICsJfQo+ICsJbWVtZmQgPSBOVUxMOwo+ICsKPiArCWV4cF9pbmZv Lm9wcyAgPSAmdWRtYWJ1Zl9vcHM7Cj4gKwlleHBfaW5mby5zaXplID0gdWJ1Zi0+cGFnZWNvdW50 IDw8IFBBR0VfU0hJRlQ7Cj4gKwlleHBfaW5mby5wcml2ID0gdWJ1ZjsKPiArCj4gKwlidWYgPSBk bWFfYnVmX2V4cG9ydCgmZXhwX2luZm8pOwo+ICsJaWYgKElTX0VSUihidWYpKSB7Cj4gKwkJcmV0 ID0gUFRSX0VSUihidWYpOwo+ICsJCWdvdG8gZXJyX3B1dF9wYWdlczsKPiArCX0KPiArCj4gKwlm bGFncyA9IDA7Cj4gKwlpZiAoaGVhZC0+ZmxhZ3MgJiBVRE1BQlVGX0ZMQUdTX0NMT0VYRUMpCj4g KwkJZmxhZ3MgfD0gT19DTE9FWEVDOwo+ICsJcmV0dXJuIGRtYV9idWZfZmQoYnVmLCBmbGFncyk7 Cj4gKwo+ICtlcnJfcHV0X3BhZ2VzOgo+ICsJd2hpbGUgKHBnYnVmID4gMCkKPiArCQlwdXRfcGFn ZSh1YnVmLT5wYWdlc1stLXBnYnVmXSk7Cj4gK2Vycl9mcmVlX3VidWY6Cj4gKwlmcHV0KG1lbWZk KTsKPiArCWtmcmVlKHVidWYtPnBhZ2VzKTsKPiArCWtmcmVlKHVidWYpOwo+ICsJcmV0dXJuIHJl dDsKPiArfQo+ICsKPiArc3RhdGljIGxvbmcgdWRtYWJ1Zl9pb2N0bF9jcmVhdGUoc3RydWN0IGZp bGUgKmZpbHAsIHVuc2lnbmVkIGxvbmcgYXJnKQo+ICt7Cj4gKwlzdHJ1Y3QgdWRtYWJ1Zl9jcmVh dGUgY3JlYXRlOwo+ICsJc3RydWN0IHVkbWFidWZfY3JlYXRlX2xpc3QgaGVhZDsKPiArCXN0cnVj dCB1ZG1hYnVmX2NyZWF0ZV9pdGVtIGxpc3Q7Cj4gKwo+ICsJaWYgKGNvcHlfZnJvbV91c2VyKCZj cmVhdGUsICh2b2lkIF9fdXNlciAqKWFyZywKPiArCQkJICAgc2l6ZW9mKHN0cnVjdCB1ZG1hYnVm X2NyZWF0ZSkpKQo+ICsJCXJldHVybiAtRUZBVUxUOwo+ICsKPiArCWhlYWQuZmxhZ3MgID0gY3Jl YXRlLmZsYWdzOwo+ICsJaGVhZC5jb3VudCAgPSAxOwo+ICsJbGlzdC5tZW1mZCAgPSBjcmVhdGUu bWVtZmQ7Cj4gKwlsaXN0Lm9mZnNldCA9IGNyZWF0ZS5vZmZzZXQ7Cj4gKwlsaXN0LnNpemUgICA9 IGNyZWF0ZS5zaXplOwo+ICsKPiArCXJldHVybiB1ZG1hYnVmX2NyZWF0ZSgmaGVhZCwgJmxpc3Qp Owo+ICt9Cj4gKwo+ICtzdGF0aWMgbG9uZyB1ZG1hYnVmX2lvY3RsX2NyZWF0ZV9saXN0KHN0cnVj dCBmaWxlICpmaWxwLCB1bnNpZ25lZCBsb25nIGFyZykKPiArewo+ICsJc3RydWN0IHVkbWFidWZf Y3JlYXRlX2xpc3QgaGVhZDsKPiArCXN0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9pdGVtICpsaXN0Owo+ ICsJaW50IHJldCA9IC1FSU5WQUw7Cj4gKwl1MzIgbHNpemU7Cj4gKwo+ICsJaWYgKGNvcHlfZnJv bV91c2VyKCZoZWFkLCAodm9pZCBfX3VzZXIgKilhcmcsIHNpemVvZihoZWFkKSkpCj4gKwkJcmV0 dXJuIC1FRkFVTFQ7Cj4gKwlpZiAoaGVhZC5jb3VudCA+IDEwMjQpCj4gKwkJcmV0dXJuIC1FSU5W QUw7Cj4gKwlsc2l6ZSA9IHNpemVvZihzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGVfaXRlbSkgKiBoZWFk LmNvdW50Owo+ICsJbGlzdCA9IG1lbWR1cF91c2VyKCh2b2lkIF9fdXNlciAqKShhcmcgKyBzaXpl b2YoaGVhZCkpLCBsc2l6ZSk7Cj4gKwlpZiAoSVNfRVJSKGxpc3QpKQo+ICsJCXJldHVybiBQVFJf RVJSKGxpc3QpOwo+ICsKPiArCXJldCA9IHVkbWFidWZfY3JlYXRlKCZoZWFkLCBsaXN0KTsKPiAr CWtmcmVlKGxpc3QpOwo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICsKPiArc3RhdGljIGxvbmcgdWRt YWJ1Zl9pb2N0bChzdHJ1Y3QgZmlsZSAqZmlscCwgdW5zaWduZWQgaW50IGlvY3RsLAo+ICsJCQkg IHVuc2lnbmVkIGxvbmcgYXJnKQo+ICt7Cj4gKwlsb25nIHJldDsKPiArCj4gKwlzd2l0Y2ggKGlv Y3RsKSB7Cj4gKwljYXNlIFVETUFCVUZfQ1JFQVRFOgo+ICsJCXJldCA9IHVkbWFidWZfaW9jdGxf Y3JlYXRlKGZpbHAsIGFyZyk7Cj4gKwkJYnJlYWs7Cj4gKwljYXNlIFVETUFCVUZfQ1JFQVRFX0xJ U1Q6Cj4gKwkJcmV0ID0gdWRtYWJ1Zl9pb2N0bF9jcmVhdGVfbGlzdChmaWxwLCBhcmcpOwo+ICsJ CWJyZWFrOwo+ICsJZGVmYXVsdDoKPiArCQlyZXQgPSAtRUlOVkFMOwo+ICsJCWJyZWFrOwo+ICsJ fQo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICsKPiArc3RhdGljIGNvbnN0IHN0cnVjdCBmaWxlX29w ZXJhdGlvbnMgdWRtYWJ1Zl9mb3BzID0gewo+ICsJLm93bmVyCQk9IFRISVNfTU9EVUxFLAo+ICsJ LnVubG9ja2VkX2lvY3RsID0gdWRtYWJ1Zl9pb2N0bCwKPiArfTsKPiArCj4gK3N0YXRpYyBzdHJ1 Y3QgbWlzY2RldmljZSB1ZG1hYnVmX21pc2MgPSB7Cj4gKwkubWlub3IgICAgICAgICAgPSBNSVND X0RZTkFNSUNfTUlOT1IsCj4gKwkubmFtZSAgICAgICAgICAgPSAidWRtYWJ1ZiIsCj4gKwkuZm9w cyAgICAgICAgICAgPSAmdWRtYWJ1Zl9mb3BzLAo+ICt9Owo+ICsKPiArc3RhdGljIGludCBfX2lu aXQgdWRtYWJ1Zl9kZXZfaW5pdCh2b2lkKQo+ICt7Cj4gKwlyZXR1cm4gbWlzY19yZWdpc3Rlcigm dWRtYWJ1Zl9taXNjKTsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgX19leGl0IHVkbWFidWZfZGV2 X2V4aXQodm9pZCkKPiArewo+ICsJbWlzY19kZXJlZ2lzdGVyKCZ1ZG1hYnVmX21pc2MpOwo+ICt9 Cj4gKwo+ICttb2R1bGVfaW5pdCh1ZG1hYnVmX2Rldl9pbml0KQo+ICttb2R1bGVfZXhpdCh1ZG1h YnVmX2Rldl9leGl0KQo+ICsKPiArTU9EVUxFX0FVVEhPUigiR2VyZCBIb2ZmbWFubiA8a3JheGVs QHJlZGhhdC5jb20+Iik7Cj4gK01PRFVMRV9MSUNFTlNFKCJHUEwgdjIiKTsKPiBkaWZmIC0tZ2l0 IGEvdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9kbWEtYnVmL3VkbWFidWYuYyBiL3Rv b2xzL3Rlc3Rpbmcvc2VsZnRlc3RzL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMKPiBuZXcgZmls ZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAwMDAuLjM3NmIxZDY3MzAKPiAtLS0gL2Rldi9u dWxsCj4gKysrIGIvdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9kbWEtYnVmL3VkbWFi dWYuYwo+IEBAIC0wLDAgKzEsOTYgQEAKPiArLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQ TC0yLjAKPiArI2luY2x1ZGUgPHN0ZGlvLmg+Cj4gKyNpbmNsdWRlIDxzdGRsaWIuaD4KPiArI2lu Y2x1ZGUgPHVuaXN0ZC5oPgo+ICsjaW5jbHVkZSA8c3RyaW5nLmg+Cj4gKyNpbmNsdWRlIDxlcnJu by5oPgo+ICsjaW5jbHVkZSA8ZmNudGwuaD4KPiArI2luY2x1ZGUgPG1hbGxvYy5oPgo+ICsKPiAr I2luY2x1ZGUgPHN5cy9pb2N0bC5oPgo+ICsjaW5jbHVkZSA8c3lzL3N5c2NhbGwuaD4KPiArI2lu Y2x1ZGUgPGxpbnV4L21lbWZkLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC91ZG1hYnVmLmg+Cj4gKwo+ ICsjZGVmaW5lIFRFU1RfUFJFRklYCSJkcml2ZXJzL2RtYS1idWYvdWRtYWJ1ZiIKPiArI2RlZmlu ZSBOVU1fUEFHRVMgICAgICAgNAo+ICsKPiArc3RhdGljIGludCBtZW1mZF9jcmVhdGUoY29uc3Qg Y2hhciAqbmFtZSwgdW5zaWduZWQgaW50IGZsYWdzKQo+ICt7Cj4gKwlyZXR1cm4gc3lzY2FsbChf X05SX21lbWZkX2NyZWF0ZSwgbmFtZSwgZmxhZ3MpOwo+ICt9Cj4gKwo+ICtpbnQgbWFpbihpbnQg YXJnYywgY2hhciAqYXJndltdKQo+ICt7Cj4gKwlzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGUgY3JlYXRl Owo+ICsJaW50IGRldmZkLCBtZW1mZCwgYnVmLCByZXQ7Cj4gKwlvZmZfdCBzaXplOwo+ICsJdm9p ZCAqbWVtOwo+ICsKPiArCWRldmZkID0gb3BlbigiL2Rldi91ZG1hYnVmIiwgT19SRFdSKTsKPiAr CWlmIChkZXZmZCA8IDApIHsKPiArCQlwcmludGYoIiVzOiBbc2tpcCxuby11ZG1hYnVmXVxuIiwg VEVTVF9QUkVGSVgpOwo+ICsJCWV4aXQoNzcpOwo+ICsJfQo+ICsKPiArCW1lbWZkID0gbWVtZmRf Y3JlYXRlKCJ1ZG1hYnVmLXRlc3QiLCBNRkRfQ0xPRVhFQyk7Cj4gKwlpZiAobWVtZmQgPCAwKSB7 Cj4gKwkJcHJpbnRmKCIlczogW3NraXAsbm8tbWVtZmRdXG4iLCBURVNUX1BSRUZJWCk7Cj4gKwkJ ZXhpdCg3Nyk7Cj4gKwl9Cj4gKwo+ICsJc2l6ZSA9IGdldHBhZ2VzaXplKCkgKiBOVU1fUEFHRVM7 Cj4gKwlyZXQgPSBmdHJ1bmNhdGUobWVtZmQsIHNpemUpOwo+ICsJaWYgKHJldCA9PSAtMSkgewo+ ICsJCXByaW50ZigiJXM6IFtGQUlMLG1lbWZkLXRydW5jYXRlXVxuIiwgVEVTVF9QUkVGSVgpOwo+ ICsJCWV4aXQoMSk7Cj4gKwl9Cj4gKwo+ICsJbWVtc2V0KCZjcmVhdGUsIDAsIHNpemVvZihjcmVh dGUpKTsKPiArCj4gKwkvKiBzaG91bGQgZmFpbCAob2Zmc2V0IG5vdCBwYWdlIGFsaWduZWQpICov Cj4gKwljcmVhdGUubWVtZmQgID0gbWVtZmQ7Cj4gKwljcmVhdGUub2Zmc2V0ID0gZ2V0cGFnZXNp emUoKS8yOwo+ICsJY3JlYXRlLnNpemUgICA9IGdldHBhZ2VzaXplKCk7Cj4gKwlidWYgPSBpb2N0 bChkZXZmZCwgVURNQUJVRl9DUkVBVEUsICZjcmVhdGUpOwo+ICsJaWYgKGJ1ZiA+PSAwKSB7Cj4g KwkJcHJpbnRmKCIlczogW0ZBSUwsdGVzdC0xXVxuIiwgVEVTVF9QUkVGSVgpOwo+ICsJCWV4aXQo MSk7Cj4gKwl9Cj4gKwo+ICsJLyogc2hvdWxkIGZhaWwgKHNpemUgbm90IG11bHRpcGxlIG9mIHBh Z2UpICovCj4gKwljcmVhdGUubWVtZmQgID0gbWVtZmQ7Cj4gKwljcmVhdGUub2Zmc2V0ID0gMDsK PiArCWNyZWF0ZS5zaXplICAgPSBnZXRwYWdlc2l6ZSgpLzI7Cj4gKwlidWYgPSBpb2N0bChkZXZm ZCwgVURNQUJVRl9DUkVBVEUsICZjcmVhdGUpOwo+ICsJaWYgKGJ1ZiA+PSAwKSB7Cj4gKwkJcHJp bnRmKCIlczogW0ZBSUwsdGVzdC0yXVxuIiwgVEVTVF9QUkVGSVgpOwo+ICsJCWV4aXQoMSk7Cj4g Kwl9Cj4gKwo+ICsJLyogc2hvdWxkIGZhaWwgKG5vdCBtZW1mZCkgKi8KPiArCWNyZWF0ZS5tZW1m ZCAgPSAwOyAvKiBzdGRpbiAqLwo+ICsJY3JlYXRlLm9mZnNldCA9IDA7Cj4gKwljcmVhdGUuc2l6 ZSAgID0gc2l6ZTsKPiArCWJ1ZiA9IGlvY3RsKGRldmZkLCBVRE1BQlVGX0NSRUFURSwgJmNyZWF0 ZSk7Cj4gKwlpZiAoYnVmID49IDApIHsKPiArCQlwcmludGYoIiVzOiBbRkFJTCx0ZXN0LTNdXG4i LCBURVNUX1BSRUZJWCk7Cj4gKwkJZXhpdCgxKTsKPiArCX0KPiArCj4gKwkvKiBzaG91bGQgd29y ayAqLwo+ICsJY3JlYXRlLm1lbWZkICA9IG1lbWZkOwo+ICsJY3JlYXRlLm9mZnNldCA9IDA7Cj4g KwljcmVhdGUuc2l6ZSAgID0gc2l6ZTsKPiArCWJ1ZiA9IGlvY3RsKGRldmZkLCBVRE1BQlVGX0NS RUFURSwgJmNyZWF0ZSk7Cj4gKwlpZiAoYnVmIDwgMCkgewo+ICsJCXByaW50ZigiJXM6IFtGQUlM LHRlc3QtNF1cbiIsIFRFU1RfUFJFRklYKTsKPiArCQlleGl0KDEpOwo+ICsJfQo+ICsKPiArCWZw cmludGYoc3RkZXJyLCAiJXM6IG9rXG4iLCBURVNUX1BSRUZJWCk7Cj4gKwljbG9zZShidWYpOwo+ ICsJY2xvc2UobWVtZmQpOwo+ICsJY2xvc2UoZGV2ZmQpOwo+ICsJcmV0dXJuIDA7Cj4gK30KPiBk aWZmIC0tZ2l0IGEvTUFJTlRBSU5FUlMgYi9NQUlOVEFJTkVSUwo+IGluZGV4IGE1YjI1NmIyNTku LjExYTliMDQyNzcgMTAwNjQ0Cj4gLS0tIGEvTUFJTlRBSU5FUlMKPiArKysgYi9NQUlOVEFJTkVS Uwo+IEBAIC0xNDkzNCw2ICsxNDkzNCwxNCBAQCBTOglNYWludGFpbmVkCj4gIEY6CURvY3VtZW50 YXRpb24vZmlsZXN5c3RlbXMvdWRmLnR4dAo+ICBGOglmcy91ZGYvCj4gIAo+ICtVRE1BQlVGIERS SVZFUgo+ICtNOglHZXJkIEhvZmZtYW5uIDxrcmF4ZWxAcmVkaGF0LmNvbT4KPiArTDoJZHJpLWRl dmVsQGxpc3RzLmZyZWVkZXNrdG9wLm9yZwo+ICtTOglNYWludGFpbmVkCj4gK0Y6CWRyaXZlcnMv ZG1hLWJ1Zi91ZG1hYnVmLmMKPiArRjoJaW5jbHVkZS91YXBpL2xpbnV4L3VkbWFidWYuaAo+ICtG Ogl0b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCgpEdXBl LCByZW1vdmUgdGhpcyBvbmUgKHNpbmNlIG9ubHkgdGhlIDJuZCBvbmUgaGFzIHRoZSBkcm0tbWlz YyBnaXQgcmVwbwplbnRyeSkuCgpBY2tlZC1ieTogRGFuaWVsIFZldHRlciA8ZGFuaWVsLnZldHRl ckBmZndsbC5jaD4KCj4gKwo+ICBVRFJBVyBUQUJMRVQKPiAgTToJQmFzdGllbiBOb2NlcmEgPGhh ZGVzc0BoYWRlc3MubmV0Pgo+ICBMOglsaW51eC1pbnB1dEB2Z2VyLmtlcm5lbC5vcmcKPiBAQCAt MTUzNDMsNiArMTUzNTEsMTQgQEAgRjoJYXJjaC94ODYvdW0vCj4gIEY6CWZzL2hvc3Rmcy8KPiAg RjoJZnMvaHBwZnMvCj4gIAo+ICtVU0VSU1BBQ0UgRE1BIEJVRkZFUiBEUklWRVIKPiArTToJR2Vy ZCBIb2ZmbWFubiA8a3JheGVsQHJlZGhhdC5jb20+Cj4gK1M6CU1haW50YWluZWQKPiArTDoJZHJp LWRldmVsQGxpc3RzLmZyZWVkZXNrdG9wLm9yZwo+ICtGOglkcml2ZXJzL2RtYS1idWYvdWRtYWJ1 Zi5jCj4gK0Y6CWluY2x1ZGUvdWFwaS9saW51eC91ZG1hYnVmLmgKPiArVDoJZ2l0IGdpdDovL2Fu b25naXQuZnJlZWRlc2t0b3Aub3JnL2RybS9kcm0tbWlzYwo+ICsKPiAgVVNFUlNQQUNFIEkvTyAo VUlPKQo+ICBNOglHcmVnIEtyb2FoLUhhcnRtYW4gPGdyZWdraEBsaW51eGZvdW5kYXRpb24ub3Jn Pgo+ICBTOglNYWludGFpbmVkCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZG1hLWJ1Zi9LY29uZmln IGIvZHJpdmVycy9kbWEtYnVmL0tjb25maWcKPiBpbmRleCBlZDNiNzg1YmFlLi4zMzgxMjllYjEy IDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvZG1hLWJ1Zi9LY29uZmlnCj4gKysrIGIvZHJpdmVycy9k bWEtYnVmL0tjb25maWcKPiBAQCAtMzAsNCArMzAsMTIgQEAgY29uZmlnIFNXX1NZTkMKPiAgCSAg V0FSTklORzogaW1wcm9wZXIgdXNlIG9mIHRoaXMgY2FuIHJlc3VsdCBpbiBkZWFkbG9ja2luZyBr ZXJuZWwKPiAgCSAgZHJpdmVycyBmcm9tIHVzZXJzcGFjZS4gSW50ZW5kZWQgZm9yIHRlc3QgYW5k IGRlYnVnIG9ubHkuCj4gIAo+ICtjb25maWcgVURNQUJVRgo+ICsJYm9vbCAidXNlcnNwYWNlIGRt YWJ1ZiBtaXNjIGRyaXZlciIKPiArCWRlZmF1bHQgbgo+ICsJZGVwZW5kcyBvbiBETUFfU0hBUkVE X0JVRkZFUgo+ICsJaGVscAo+ICsJICBBIGRyaXZlciB0byBsZXQgdXNlcnNwYWNlIHR1cm4gbWVt ZmQgcmVnaW9ucyBpbnRvIGRtYS1idWZzLgo+ICsJICBRZW11IGNhbiB1c2UgdGhpcyB0byBjcmVh dGUgaG9zdCBkbWFidWZzIGZvciBndWVzdCBmcmFtZWJ1ZmZlcnMuCj4gKwo+ICBlbmRtZW51Cj4g ZGlmZiAtLWdpdCBhL2RyaXZlcnMvZG1hLWJ1Zi9NYWtlZmlsZSBiL2RyaXZlcnMvZG1hLWJ1Zi9N YWtlZmlsZQo+IGluZGV4IGMzM2JmODg2MzEuLjA5MTNhNmNjYWIgMTAwNjQ0Cj4gLS0tIGEvZHJp dmVycy9kbWEtYnVmL01ha2VmaWxlCj4gKysrIGIvZHJpdmVycy9kbWEtYnVmL01ha2VmaWxlCj4g QEAgLTEsMyArMSw0IEBACj4gIG9iai15IDo9IGRtYS1idWYubyBkbWEtZmVuY2UubyBkbWEtZmVu Y2UtYXJyYXkubyByZXNlcnZhdGlvbi5vIHNlcW5vLWZlbmNlLm8KPiAgb2JqLSQoQ09ORklHX1NZ TkNfRklMRSkJCSs9IHN5bmNfZmlsZS5vCj4gIG9iai0kKENPTkZJR19TV19TWU5DKQkJKz0gc3df c3luYy5vIHN5bmNfZGVidWcubwo+ICtvYmotJChDT05GSUdfVURNQUJVRikJCSs9IHVkbWFidWYu bwo+IGRpZmYgLS1naXQgYS90b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1idWYv TWFrZWZpbGUgYi90b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1idWYvTWFrZWZp bGUKPiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAwMDAuLjQxNTRjM2Q3YWEK PiAtLS0gL2Rldi9udWxsCj4gKysrIGIvdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9k bWEtYnVmL01ha2VmaWxlCj4gQEAgLTAsMCArMSw1IEBACj4gK0NGTEFHUyArPSAtSS4uLy4uLy4u Ly4uLy4uL3Vzci9pbmNsdWRlLwo+ICsKPiArVEVTVF9HRU5fUFJPR1MgOj0gdWRtYWJ1Zgo+ICsK PiAraW5jbHVkZSAuLi8uLi9saWIubWsKPiAtLSAKPiAyLjkuMwo+IAoKLS0gCkRhbmllbCBWZXR0 ZXIKU29mdHdhcmUgRW5naW5lZXIsIEludGVsIENvcnBvcmF0aW9uCmh0dHA6Ly9ibG9nLmZmd2xs LmNoCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fCmRyaS1k ZXZlbCBtYWlsaW5nIGxpc3QKZHJpLWRldmVsQGxpc3RzLmZyZWVkZXNrdG9wLm9yZwpodHRwczov L2xpc3RzLmZyZWVkZXNrdG9wLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2RyaS1kZXZlbAo=