From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6BEEEC6778A for ; Tue, 3 Jul 2018 07:54:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 148FF24DE5 for ; Tue, 3 Jul 2018 07:54:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 148FF24DE5 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933611AbeGCHyG (ORCPT ); Tue, 3 Jul 2018 03:54:06 -0400 Received: from mx1.redhat.com ([209.132.183.28]:60616 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753557AbeGCHyE (ORCPT ); Tue, 3 Jul 2018 03:54:04 -0400 Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9F9B87F7C0; Tue, 3 Jul 2018 07:54:03 +0000 (UTC) Received: from sirius.home.kraxel.org (ovpn-116-220.phx2.redhat.com [10.3.116.220]) by smtp.corp.redhat.com (Postfix) with ESMTP id D5C96300193B; Tue, 3 Jul 2018 07:54:00 +0000 (UTC) Received: by sirius.home.kraxel.org (Postfix, from userid 1000) id 78D8817442; Tue, 3 Jul 2018 09:53:59 +0200 (CEST) From: Gerd Hoffmann To: dri-devel@lists.freedesktop.org Cc: Gerd Hoffmann , David Airlie , Tomeu Vizoso , Laurent Pinchart , Daniel Vetter , Jonathan Corbet , Sumit Semwal , Shuah Khan , linux-doc@vger.kernel.org (open list:DOCUMENTATION), linux-kernel@vger.kernel.org (open list), linux-media@vger.kernel.org (open list:DMA BUFFER SHARING FRAMEWORK), linaro-mm-sig@lists.linaro.org (moderated list:DMA BUFFER SHARING FRAMEWORK), linux-kselftest@vger.kernel.org (open list:KERNEL SELFTEST FRAMEWORK) Subject: [PATCH v6] Add udmabuf misc device Date: Tue, 3 Jul 2018 09:53:58 +0200 Message-Id: <20180703075359.30349-1-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.84 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 03 Jul 2018 07:54:04 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 | 8 + drivers/dma-buf/Kconfig | 8 + drivers/dma-buf/Makefile | 1 + tools/testing/selftests/drivers/dma-buf/Makefile | 5 + 8 files changed, 439 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 480c8609dc..6636dea476 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -271,6 +271,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 07d1576fc7..a8e1bb3bc3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14638,6 +14638,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 + UDRAW TABLET M: Bastien Nocera L: linux-input@vger.kernel.org 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 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.8 required=5.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham 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 443647D09E for ; Tue, 3 Jul 2018 07:54:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932394AbeGCHyF (ORCPT ); Tue, 3 Jul 2018 03:54:05 -0400 Received: from mx1.redhat.com ([209.132.183.28]:60616 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753557AbeGCHyE (ORCPT ); Tue, 3 Jul 2018 03:54:04 -0400 Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9F9B87F7C0; Tue, 3 Jul 2018 07:54:03 +0000 (UTC) Received: from sirius.home.kraxel.org (ovpn-116-220.phx2.redhat.com [10.3.116.220]) by smtp.corp.redhat.com (Postfix) with ESMTP id D5C96300193B; Tue, 3 Jul 2018 07:54:00 +0000 (UTC) Received: by sirius.home.kraxel.org (Postfix, from userid 1000) id 78D8817442; Tue, 3 Jul 2018 09:53:59 +0200 (CEST) From: Gerd Hoffmann To: dri-devel@lists.freedesktop.org Cc: Gerd Hoffmann , David Airlie , Tomeu Vizoso , Laurent Pinchart , Daniel Vetter , Jonathan Corbet , Sumit Semwal , Shuah Khan , linux-doc@vger.kernel.org (open list:DOCUMENTATION), linux-kernel@vger.kernel.org (open list), linux-media@vger.kernel.org (open list:DMA BUFFER SHARING FRAMEWORK), linaro-mm-sig@lists.linaro.org (moderated list:DMA BUFFER SHARING FRAMEWORK), linux-kselftest@vger.kernel.org (open list:KERNEL SELFTEST FRAMEWORK) Subject: [PATCH v6] Add udmabuf misc device Date: Tue, 3 Jul 2018 09:53:58 +0200 Message-Id: <20180703075359.30349-1-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.84 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 03 Jul 2018 07:54:04 +0000 (UTC) Sender: linux-doc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-doc@vger.kernel.org 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 | 8 + drivers/dma-buf/Kconfig | 8 + drivers/dma-buf/Makefile | 1 + tools/testing/selftests/drivers/dma-buf/Makefile | 5 + 8 files changed, 439 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 480c8609dc..6636dea476 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -271,6 +271,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 07d1576fc7..a8e1bb3bc3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14638,6 +14638,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 + UDRAW TABLET M: Bastien Nocera L: linux-input@vger.kernel.org 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 -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html From mboxrd@z Thu Jan 1 00:00:00 1970 From: kraxel at redhat.com (Gerd Hoffmann) Date: Tue, 3 Jul 2018 09:53:58 +0200 Subject: [PATCH v6] Add udmabuf misc device Message-ID: <20180703075359.30349-1-kraxel@redhat.com> 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 | 8 + drivers/dma-buf/Kconfig | 8 + drivers/dma-buf/Makefile | 1 + tools/testing/selftests/drivers/dma-buf/Makefile | 5 + 8 files changed, 439 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 480c8609dc..6636dea476 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -271,6 +271,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 07d1576fc7..a8e1bb3bc3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14638,6 +14638,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 + UDRAW TABLET M: Bastien Nocera L: linux-input at vger.kernel.org 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 -- To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html From mboxrd@z Thu Jan 1 00:00:00 1970 From: kraxel@redhat.com (Gerd Hoffmann) Date: Tue, 3 Jul 2018 09:53:58 +0200 Subject: [PATCH v6] Add udmabuf misc device Message-ID: <20180703075359.30349-1-kraxel@redhat.com> Content-Type: text/plain; charset="UTF-8" Message-ID: <20180703075358.bofTazltd9BUO4xgHZpW4p0KP0SYV9tJdgXRvxv7SPw@z> 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 | 8 + drivers/dma-buf/Kconfig | 8 + drivers/dma-buf/Makefile | 1 + tools/testing/selftests/drivers/dma-buf/Makefile | 5 + 8 files changed, 439 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 480c8609dc..6636dea476 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -271,6 +271,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 07d1576fc7..a8e1bb3bc3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14638,6 +14638,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 + UDRAW TABLET M: Bastien Nocera L: linux-input at vger.kernel.org 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 -- To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html From mboxrd@z Thu Jan 1 00:00:00 1970 From: Gerd Hoffmann Subject: [PATCH v6] Add udmabuf misc device Date: Tue, 3 Jul 2018 09:53:58 +0200 Message-ID: <20180703075359.30349-1-kraxel@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by gabe.freedesktop.org (Postfix) with ESMTPS id 690576E56E for ; Tue, 3 Jul 2018 07:54:04 +0000 (UTC) List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: dri-devel@lists.freedesktop.org Cc: "open list:KERNEL SELFTEST FRAMEWORK" , Tomeu Vizoso , Jonathan Corbet , David Airlie , "open list:DOCUMENTATION" , open list , "moderated list:DMA BUFFER SHARING FRAMEWORK" , Gerd Hoffmann , "open list:DMA BUFFER SHARING FRAMEWORK" , Shuah Khan , Laurent Pinchart List-Id: dri-devel@lists.freedesktop.org QSBkcml2ZXIgdG8gbGV0IHVzZXJzcGFjZSB0dXJuIG1lbWZkIHJlZ2lvbnMgaW50byBkbWEtYnVm cy4KClVzZSBjYXNlOiAgQWxsb3dzIHFlbXUgY3JlYXRlIGRtYWJ1ZnMgZm9yIHRoZSB2Z2EgZnJh bWVidWZmZXIgb3IKdmlydGlvLWdwdSByZXNzb3VyY2VzLiAgVGhlbiB0aGV5IGNhbiBiZSBwYXNz ZWQgYXJvdW5kIHRvIGRpc3BsYXkKdGhvc2UgZ3Vlc3QgdGhpbmdzIG9uIHRoZSBob3N0LiAgVG8g c3BpY2UgY2xpZW50IGZvciBjbGFzc2ljIGZ1bGwKZnJhbWVidWZmZXIgZGlzcGxheSwgYW5kIGhv cGVmdWxseSBzb21lIGRheSB0byB3YXlsYW5kIHNlcnZlciBmb3IKc2VhbWxlc3MgZ3Vlc3Qgd2lu ZG93IGRpc3BsYXkuCgpxZW11IHRlc3QgYnJhbmNoOgogIGh0dHBzOi8vZ2l0LmtyYXhlbC5vcmcv Y2dpdC9xZW11L2xvZy8/aD1zaXJpdXMvdWRtYWJ1ZgoKQ2M6IERhdmlkIEFpcmxpZSA8YWlybGll ZEBsaW51eC5pZT4KQ2M6IFRvbWV1IFZpem9zbyA8dG9tZXUudml6b3NvQGNvbGxhYm9yYS5jb20+ CkNjOiBMYXVyZW50IFBpbmNoYXJ0IDxsYXVyZW50LnBpbmNoYXJ0QGlkZWFzb25ib2FyZC5jb20+ CkNjOiBEYW5pZWwgVmV0dGVyIDxkYW5pZWxAZmZ3bGwuY2g+ClNpZ25lZC1vZmYtYnk6IEdlcmQg SG9mZm1hbm4gPGtyYXhlbEByZWRoYXQuY29tPgotLS0KIERvY3VtZW50YXRpb24vaW9jdGwvaW9j dGwtbnVtYmVyLnR4dCAgICAgICAgICAgICAgfCAgIDEgKwogaW5jbHVkZS91YXBpL2xpbnV4L3Vk bWFidWYuaCAgICAgICAgICAgICAgICAgICAgICB8ICAzMyArKysKIGRyaXZlcnMvZG1hLWJ1Zi91 ZG1hYnVmLmMgICAgICAgICAgICAgICAgICAgICAgICAgfCAyODcgKysrKysrKysrKysrKysrKysr KysrKwogdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9kbWEtYnVmL3VkbWFidWYuYyB8 ICA5NiArKysrKysrKwogTUFJTlRBSU5FUlMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICB8ICAgOCArCiBkcml2ZXJzL2RtYS1idWYvS2NvbmZpZyAgICAgICAgICAgICAgICAg ICAgICAgICAgIHwgICA4ICsKIGRyaXZlcnMvZG1hLWJ1Zi9NYWtlZmlsZSAgICAgICAgICAgICAg ICAgICAgICAgICAgfCAgIDEgKwogdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9kbWEt YnVmL01ha2VmaWxlICB8ICAgNSArCiA4IGZpbGVzIGNoYW5nZWQsIDQzOSBpbnNlcnRpb25zKCsp CiBjcmVhdGUgbW9kZSAxMDA2NDQgaW5jbHVkZS91YXBpL2xpbnV4L3VkbWFidWYuaAogY3JlYXRl IG1vZGUgMTAwNjQ0IGRyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMKIGNyZWF0ZSBtb2RlIDEwMDY0 NCB0b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCiBjcmVh dGUgbW9kZSAxMDA2NDQgdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9kbWEtYnVmL01h a2VmaWxlCgpkaWZmIC0tZ2l0IGEvRG9jdW1lbnRhdGlvbi9pb2N0bC9pb2N0bC1udW1iZXIudHh0 IGIvRG9jdW1lbnRhdGlvbi9pb2N0bC9pb2N0bC1udW1iZXIudHh0CmluZGV4IDQ4MGM4NjA5ZGMu LjY2MzZkZWE0NzYgMTAwNjQ0Ci0tLSBhL0RvY3VtZW50YXRpb24vaW9jdGwvaW9jdGwtbnVtYmVy LnR4dAorKysgYi9Eb2N1bWVudGF0aW9uL2lvY3RsL2lvY3RsLW51bWJlci50eHQKQEAgLTI3MSw2 ICsyNzEsNyBAQCBDb2RlICBTZXEjKGhleCkJSW5jbHVkZSBGaWxlCQlDb21tZW50cwogJ3QnCTkw LTkxCWxpbnV4L3Rvc2hpYmEuaAkJdG9zaGliYSBhbmQgdG9zaGliYV9hY3BpIFNNTQogJ3UnCTAw LTFGCWxpbnV4L3NtYl9mcy5oCQlnb25lCiAndScJMjAtM0YJbGludXgvdXZjdmlkZW8uaAlVU0Ig dmlkZW8gY2xhc3MgaG9zdCBkcml2ZXIKKyd1Jwk0MC00ZglsaW51eC91ZG1hYnVmLmgJCXVzZXJz cGFjZSBkbWEtYnVmIG1pc2MgZGV2aWNlCiAndicJMDAtMUYJbGludXgvZXh0Ml9mcy5oCQljb25m bGljdCEKICd2JwkwMC0xRglsaW51eC9mcy5oCQljb25mbGljdCEKICd2JwkwMC0wRglsaW51eC9z b255cGkuaAkJY29uZmxpY3QhCmRpZmYgLS1naXQgYS9pbmNsdWRlL3VhcGkvbGludXgvdWRtYWJ1 Zi5oIGIvaW5jbHVkZS91YXBpL2xpbnV4L3VkbWFidWYuaApuZXcgZmlsZSBtb2RlIDEwMDY0NApp bmRleCAwMDAwMDAwMDAwLi40NmI2NTMyZWQ4Ci0tLSAvZGV2L251bGwKKysrIGIvaW5jbHVkZS91 YXBpL2xpbnV4L3VkbWFidWYuaApAQCAtMCwwICsxLDMzIEBACisvKiBTUERYLUxpY2Vuc2UtSWRl bnRpZmllcjogR1BMLTIuMCBXSVRIIExpbnV4LXN5c2NhbGwtbm90ZSAqLworI2lmbmRlZiBfVUFQ SV9MSU5VWF9VRE1BQlVGX0gKKyNkZWZpbmUgX1VBUElfTElOVVhfVURNQUJVRl9ICisKKyNpbmNs dWRlIDxsaW51eC90eXBlcy5oPgorI2luY2x1ZGUgPGxpbnV4L2lvY3RsLmg+CisKKyNkZWZpbmUg VURNQUJVRl9GTEFHU19DTE9FWEVDCTB4MDEKKworc3RydWN0IHVkbWFidWZfY3JlYXRlIHsKKwlf X3UzMiBtZW1mZDsKKwlfX3UzMiBmbGFnczsKKwlfX3U2NCBvZmZzZXQ7CisJX191NjQgc2l6ZTsK K307CisKK3N0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9pdGVtIHsKKwlfX3UzMiBtZW1mZDsKKwlfX3Uz MiBfX3BhZDsKKwlfX3U2NCBvZmZzZXQ7CisJX191NjQgc2l6ZTsKK307CisKK3N0cnVjdCB1ZG1h YnVmX2NyZWF0ZV9saXN0IHsKKwlfX3UzMiBmbGFnczsKKwlfX3UzMiBjb3VudDsKKwlzdHJ1Y3Qg dWRtYWJ1Zl9jcmVhdGVfaXRlbSBsaXN0W107Cit9OworCisjZGVmaW5lIFVETUFCVUZfQ1JFQVRF ICAgICAgIF9JT1coJ3UnLCAweDQyLCBzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGUpCisjZGVmaW5lIFVE TUFCVUZfQ1JFQVRFX0xJU1QgIF9JT1coJ3UnLCAweDQzLCBzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGVf bGlzdCkKKworI2VuZGlmIC8qIF9VQVBJX0xJTlVYX1VETUFCVUZfSCAqLwpkaWZmIC0tZ2l0IGEv ZHJpdmVycy9kbWEtYnVmL3VkbWFidWYuYyBiL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMKbmV3 IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMDAwMC4uOGUyNDIwNDUyNgotLS0gL2Rldi9u dWxsCisrKyBiL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMKQEAgLTAsMCArMSwyODcgQEAKKy8v IFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wCisjaW5jbHVkZSA8bGludXgvaW5pdC5o PgorI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgorI2luY2x1ZGUgPGxpbnV4L2RldmljZS5oPgor I2luY2x1ZGUgPGxpbnV4L2tlcm5lbC5oPgorI2luY2x1ZGUgPGxpbnV4L3NsYWIuaD4KKyNpbmNs dWRlIDxsaW51eC9taXNjZGV2aWNlLmg+CisjaW5jbHVkZSA8bGludXgvZG1hLWJ1Zi5oPgorI2lu Y2x1ZGUgPGxpbnV4L2hpZ2htZW0uaD4KKyNpbmNsdWRlIDxsaW51eC9jcmVkLmg+CisjaW5jbHVk ZSA8bGludXgvc2htZW1fZnMuaD4KKyNpbmNsdWRlIDxsaW51eC9tZW1mZC5oPgorCisjaW5jbHVk ZSA8dWFwaS9saW51eC91ZG1hYnVmLmg+CisKK3N0cnVjdCB1ZG1hYnVmIHsKKwl1MzIgcGFnZWNv dW50OworCXN0cnVjdCBwYWdlICoqcGFnZXM7Cit9OworCitzdGF0aWMgaW50IHVkbWFidWZfdm1f ZmF1bHQoc3RydWN0IHZtX2ZhdWx0ICp2bWYpCit7CisJc3RydWN0IHZtX2FyZWFfc3RydWN0ICp2 bWEgPSB2bWYtPnZtYTsKKwlzdHJ1Y3QgdWRtYWJ1ZiAqdWJ1ZiA9IHZtYS0+dm1fcHJpdmF0ZV9k YXRhOworCisJaWYgKFdBUk5fT04odm1mLT5wZ29mZiA+PSB1YnVmLT5wYWdlY291bnQpKQorCQly ZXR1cm4gVk1fRkFVTFRfU0lHQlVTOworCisJdm1mLT5wYWdlID0gdWJ1Zi0+cGFnZXNbdm1mLT5w Z29mZl07CisJZ2V0X3BhZ2Uodm1mLT5wYWdlKTsKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGNv bnN0IHN0cnVjdCB2bV9vcGVyYXRpb25zX3N0cnVjdCB1ZG1hYnVmX3ZtX29wcyA9IHsKKwkuZmF1 bHQgPSB1ZG1hYnVmX3ZtX2ZhdWx0LAorfTsKKworc3RhdGljIGludCBtbWFwX3VkbWFidWYoc3Ry dWN0IGRtYV9idWYgKmJ1Ziwgc3RydWN0IHZtX2FyZWFfc3RydWN0ICp2bWEpCit7CisJc3RydWN0 IHVkbWFidWYgKnVidWYgPSBidWYtPnByaXY7CisKKwlpZiAoKHZtYS0+dm1fZmxhZ3MgJiAoVk1f U0hBUkVEIHwgVk1fTUFZU0hBUkUpKSA9PSAwKQorCQlyZXR1cm4gLUVJTlZBTDsKKworCXZtYS0+ dm1fb3BzID0gJnVkbWFidWZfdm1fb3BzOworCXZtYS0+dm1fcHJpdmF0ZV9kYXRhID0gdWJ1ZjsK KwlyZXR1cm4gMDsKK30KKworc3RhdGljIHN0cnVjdCBzZ190YWJsZSAqbWFwX3VkbWFidWYoc3Ry dWN0IGRtYV9idWZfYXR0YWNobWVudCAqYXQsCisJCQkJICAgIGVudW0gZG1hX2RhdGFfZGlyZWN0 aW9uIGRpcmVjdGlvbikKK3sKKwlzdHJ1Y3QgdWRtYWJ1ZiAqdWJ1ZiA9IGF0LT5kbWFidWYtPnBy aXY7CisJc3RydWN0IHNnX3RhYmxlICpzZzsKKworCXNnID0ga3phbGxvYyhzaXplb2YoKnNnKSwg R0ZQX0tFUk5FTCk7CisJaWYgKCFzZykKKwkJZ290byBlcnIxOworCWlmIChzZ19hbGxvY190YWJs ZV9mcm9tX3BhZ2VzKHNnLCB1YnVmLT5wYWdlcywgdWJ1Zi0+cGFnZWNvdW50LAorCQkJCSAgICAg IDAsIHVidWYtPnBhZ2Vjb3VudCA8PCBQQUdFX1NISUZULAorCQkJCSAgICAgIEdGUF9LRVJORUwp IDwgMCkKKwkJZ290byBlcnIyOworCWlmICghZG1hX21hcF9zZyhhdC0+ZGV2LCBzZy0+c2dsLCBz Zy0+bmVudHMsIGRpcmVjdGlvbikpCisJCWdvdG8gZXJyMzsKKworCXJldHVybiBzZzsKKworZXJy MzoKKwlzZ19mcmVlX3RhYmxlKHNnKTsKK2VycjI6CisJa2ZyZWUoc2cpOworZXJyMToKKwlyZXR1 cm4gRVJSX1BUUigtRU5PTUVNKTsKK30KKworc3RhdGljIHZvaWQgdW5tYXBfdWRtYWJ1ZihzdHJ1 Y3QgZG1hX2J1Zl9hdHRhY2htZW50ICphdCwKKwkJCSAgc3RydWN0IHNnX3RhYmxlICpzZywKKwkJ CSAgZW51bSBkbWFfZGF0YV9kaXJlY3Rpb24gZGlyZWN0aW9uKQoreworCXNnX2ZyZWVfdGFibGUo c2cpOworCWtmcmVlKHNnKTsKK30KKworc3RhdGljIHZvaWQgcmVsZWFzZV91ZG1hYnVmKHN0cnVj dCBkbWFfYnVmICpidWYpCit7CisJc3RydWN0IHVkbWFidWYgKnVidWYgPSBidWYtPnByaXY7CisJ cGdvZmZfdCBwZzsKKworCWZvciAocGcgPSAwOyBwZyA8IHVidWYtPnBhZ2Vjb3VudDsgcGcrKykK KwkJcHV0X3BhZ2UodWJ1Zi0+cGFnZXNbcGddKTsKKwlrZnJlZSh1YnVmLT5wYWdlcyk7CisJa2Zy ZWUodWJ1Zik7Cit9CisKK3N0YXRpYyB2b2lkICprbWFwX3VkbWFidWYoc3RydWN0IGRtYV9idWYg KmJ1ZiwgdW5zaWduZWQgbG9uZyBwYWdlX251bSkKK3sKKwlzdHJ1Y3QgdWRtYWJ1ZiAqdWJ1ZiA9 IGJ1Zi0+cHJpdjsKKwlzdHJ1Y3QgcGFnZSAqcGFnZSA9IHVidWYtPnBhZ2VzW3BhZ2VfbnVtXTsK KworCXJldHVybiBrbWFwKHBhZ2UpOworfQorCitzdGF0aWMgdm9pZCBrdW5tYXBfdWRtYWJ1Zihz dHJ1Y3QgZG1hX2J1ZiAqYnVmLCB1bnNpZ25lZCBsb25nIHBhZ2VfbnVtLAorCQkJICAgdm9pZCAq dmFkZHIpCit7CisJa3VubWFwKHZhZGRyKTsKK30KKworc3RhdGljIHN0cnVjdCBkbWFfYnVmX29w cyB1ZG1hYnVmX29wcyA9IHsKKwkubWFwX2RtYV9idWYJICA9IG1hcF91ZG1hYnVmLAorCS51bm1h cF9kbWFfYnVmCSAgPSB1bm1hcF91ZG1hYnVmLAorCS5yZWxlYXNlCSAgPSByZWxlYXNlX3VkbWFi dWYsCisJLm1hcAkJICA9IGttYXBfdWRtYWJ1ZiwKKwkudW5tYXAJCSAgPSBrdW5tYXBfdWRtYWJ1 ZiwKKwkubW1hcAkJICA9IG1tYXBfdWRtYWJ1ZiwKK307CisKKyNkZWZpbmUgU0VBTFNfV0FOVEVE IChGX1NFQUxfU0hSSU5LKQorI2RlZmluZSBTRUFMU19ERU5JRUQgKEZfU0VBTF9XUklURSkKKwor c3RhdGljIGxvbmcgdWRtYWJ1Zl9jcmVhdGUoc3RydWN0IHVkbWFidWZfY3JlYXRlX2xpc3QgKmhl YWQsCisJCQkgICBzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGVfaXRlbSAqbGlzdCkKK3sKKwlERUZJTkVf RE1BX0JVRl9FWFBPUlRfSU5GTyhleHBfaW5mbyk7CisJc3RydWN0IGZpbGUgKm1lbWZkID0gTlVM TDsKKwlzdHJ1Y3QgdWRtYWJ1ZiAqdWJ1ZjsKKwlzdHJ1Y3QgZG1hX2J1ZiAqYnVmOworCXBnb2Zm X3QgcGdvZmYsIHBnY250LCBwZ2lkeCwgcGdidWY7CisJc3RydWN0IHBhZ2UgKnBhZ2U7CisJaW50 IHNlYWxzLCByZXQgPSAtRUlOVkFMOworCXUzMiBpLCBmbGFnczsKKworCXVidWYgPSBremFsbG9j KHNpemVvZihzdHJ1Y3QgdWRtYWJ1ZiksIEdGUF9LRVJORUwpOworCWlmICghdWJ1ZikKKwkJcmV0 dXJuIC1FTk9NRU07CisKKwlmb3IgKGkgPSAwOyBpIDwgaGVhZC0+Y291bnQ7IGkrKykgeworCQlp ZiAoIUlTX0FMSUdORUQobGlzdFtpXS5vZmZzZXQsIFBBR0VfU0laRSkpCisJCQlnb3RvIGVycl9m cmVlX3VidWY7CisJCWlmICghSVNfQUxJR05FRChsaXN0W2ldLnNpemUsIFBBR0VfU0laRSkpCisJ CQlnb3RvIGVycl9mcmVlX3VidWY7CisJCXVidWYtPnBhZ2Vjb3VudCArPSBsaXN0W2ldLnNpemUg Pj4gUEFHRV9TSElGVDsKKwl9CisJdWJ1Zi0+cGFnZXMgPSBrbWFsbG9jX2FycmF5KHVidWYtPnBh Z2Vjb3VudCwgc2l6ZW9mKHN0cnVjdCBwYWdlICopLAorCQkJCSAgICBHRlBfS0VSTkVMKTsKKwlp ZiAoIXVidWYtPnBhZ2VzKSB7CisJCXJldCA9IC1FTk9NRU07CisJCWdvdG8gZXJyX2ZyZWVfdWJ1 ZjsKKwl9CisKKwlwZ2J1ZiA9IDA7CisJZm9yIChpID0gMDsgaSA8IGhlYWQtPmNvdW50OyBpKysp IHsKKwkJbWVtZmQgPSBmZ2V0KGxpc3RbaV0ubWVtZmQpOworCQlpZiAoIW1lbWZkKQorCQkJZ290 byBlcnJfcHV0X3BhZ2VzOworCQlpZiAoIXNobWVtX21hcHBpbmcoZmlsZV9pbm9kZShtZW1mZCkt PmlfbWFwcGluZykpCisJCQlnb3RvIGVycl9wdXRfcGFnZXM7CisJCXNlYWxzID0gbWVtZmRfZmNu dGwobWVtZmQsIEZfR0VUX1NFQUxTLCAwKTsKKwkJaWYgKHNlYWxzID09IC1FSU5WQUwgfHwKKwkJ ICAgIChzZWFscyAmIFNFQUxTX1dBTlRFRCkgIT0gU0VBTFNfV0FOVEVEIHx8CisJCSAgICAoc2Vh bHMgJiBTRUFMU19ERU5JRUQpICE9IDApCisJCQlnb3RvIGVycl9wdXRfcGFnZXM7CisJCXBnb2Zm ID0gbGlzdFtpXS5vZmZzZXQgPj4gUEFHRV9TSElGVDsKKwkJcGdjbnQgPSBsaXN0W2ldLnNpemUg ICA+PiBQQUdFX1NISUZUOworCQlmb3IgKHBnaWR4ID0gMDsgcGdpZHggPCBwZ2NudDsgcGdpZHgr KykgeworCQkJcGFnZSA9IHNobWVtX3JlYWRfbWFwcGluZ19wYWdlKAorCQkJCWZpbGVfaW5vZGUo bWVtZmQpLT5pX21hcHBpbmcsIHBnb2ZmICsgcGdpZHgpOworCQkJaWYgKElTX0VSUihwYWdlKSkg eworCQkJCXJldCA9IFBUUl9FUlIocGFnZSk7CisJCQkJZ290byBlcnJfcHV0X3BhZ2VzOworCQkJ fQorCQkJdWJ1Zi0+cGFnZXNbcGdidWYrK10gPSBwYWdlOworCQl9CisJCWZwdXQobWVtZmQpOwor CX0KKwltZW1mZCA9IE5VTEw7CisKKwlleHBfaW5mby5vcHMgID0gJnVkbWFidWZfb3BzOworCWV4 cF9pbmZvLnNpemUgPSB1YnVmLT5wYWdlY291bnQgPDwgUEFHRV9TSElGVDsKKwlleHBfaW5mby5w cml2ID0gdWJ1ZjsKKworCWJ1ZiA9IGRtYV9idWZfZXhwb3J0KCZleHBfaW5mbyk7CisJaWYgKElT X0VSUihidWYpKSB7CisJCXJldCA9IFBUUl9FUlIoYnVmKTsKKwkJZ290byBlcnJfcHV0X3BhZ2Vz OworCX0KKworCWZsYWdzID0gMDsKKwlpZiAoaGVhZC0+ZmxhZ3MgJiBVRE1BQlVGX0ZMQUdTX0NM T0VYRUMpCisJCWZsYWdzIHw9IE9fQ0xPRVhFQzsKKwlyZXR1cm4gZG1hX2J1Zl9mZChidWYsIGZs YWdzKTsKKworZXJyX3B1dF9wYWdlczoKKwl3aGlsZSAocGdidWYgPiAwKQorCQlwdXRfcGFnZSh1 YnVmLT5wYWdlc1stLXBnYnVmXSk7CitlcnJfZnJlZV91YnVmOgorCWZwdXQobWVtZmQpOworCWtm cmVlKHVidWYtPnBhZ2VzKTsKKwlrZnJlZSh1YnVmKTsKKwlyZXR1cm4gcmV0OworfQorCitzdGF0 aWMgbG9uZyB1ZG1hYnVmX2lvY3RsX2NyZWF0ZShzdHJ1Y3QgZmlsZSAqZmlscCwgdW5zaWduZWQg bG9uZyBhcmcpCit7CisJc3RydWN0IHVkbWFidWZfY3JlYXRlIGNyZWF0ZTsKKwlzdHJ1Y3QgdWRt YWJ1Zl9jcmVhdGVfbGlzdCBoZWFkOworCXN0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9pdGVtIGxpc3Q7 CisKKwlpZiAoY29weV9mcm9tX3VzZXIoJmNyZWF0ZSwgKHZvaWQgX191c2VyICopYXJnLAorCQkJ ICAgc2l6ZW9mKHN0cnVjdCB1ZG1hYnVmX2NyZWF0ZSkpKQorCQlyZXR1cm4gLUVGQVVMVDsKKwor CWhlYWQuZmxhZ3MgID0gY3JlYXRlLmZsYWdzOworCWhlYWQuY291bnQgID0gMTsKKwlsaXN0Lm1l bWZkICA9IGNyZWF0ZS5tZW1mZDsKKwlsaXN0Lm9mZnNldCA9IGNyZWF0ZS5vZmZzZXQ7CisJbGlz dC5zaXplICAgPSBjcmVhdGUuc2l6ZTsKKworCXJldHVybiB1ZG1hYnVmX2NyZWF0ZSgmaGVhZCwg Jmxpc3QpOworfQorCitzdGF0aWMgbG9uZyB1ZG1hYnVmX2lvY3RsX2NyZWF0ZV9saXN0KHN0cnVj dCBmaWxlICpmaWxwLCB1bnNpZ25lZCBsb25nIGFyZykKK3sKKwlzdHJ1Y3QgdWRtYWJ1Zl9jcmVh dGVfbGlzdCBoZWFkOworCXN0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9pdGVtICpsaXN0OworCWludCBy ZXQgPSAtRUlOVkFMOworCXUzMiBsc2l6ZTsKKworCWlmIChjb3B5X2Zyb21fdXNlcigmaGVhZCwg KHZvaWQgX191c2VyICopYXJnLCBzaXplb2YoaGVhZCkpKQorCQlyZXR1cm4gLUVGQVVMVDsKKwlp ZiAoaGVhZC5jb3VudCA+IDEwMjQpCisJCXJldHVybiAtRUlOVkFMOworCWxzaXplID0gc2l6ZW9m KHN0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9pdGVtKSAqIGhlYWQuY291bnQ7CisJbGlzdCA9IG1lbWR1 cF91c2VyKCh2b2lkIF9fdXNlciAqKShhcmcgKyBzaXplb2YoaGVhZCkpLCBsc2l6ZSk7CisJaWYg KElTX0VSUihsaXN0KSkKKwkJcmV0dXJuIFBUUl9FUlIobGlzdCk7CisKKwlyZXQgPSB1ZG1hYnVm X2NyZWF0ZSgmaGVhZCwgbGlzdCk7CisJa2ZyZWUobGlzdCk7CisJcmV0dXJuIHJldDsKK30KKwor c3RhdGljIGxvbmcgdWRtYWJ1Zl9pb2N0bChzdHJ1Y3QgZmlsZSAqZmlscCwgdW5zaWduZWQgaW50 IGlvY3RsLAorCQkJICB1bnNpZ25lZCBsb25nIGFyZykKK3sKKwlsb25nIHJldDsKKworCXN3aXRj aCAoaW9jdGwpIHsKKwljYXNlIFVETUFCVUZfQ1JFQVRFOgorCQlyZXQgPSB1ZG1hYnVmX2lvY3Rs X2NyZWF0ZShmaWxwLCBhcmcpOworCQlicmVhazsKKwljYXNlIFVETUFCVUZfQ1JFQVRFX0xJU1Q6 CisJCXJldCA9IHVkbWFidWZfaW9jdGxfY3JlYXRlX2xpc3QoZmlscCwgYXJnKTsKKwkJYnJlYWs7 CisJZGVmYXVsdDoKKwkJcmV0ID0gLUVJTlZBTDsKKwkJYnJlYWs7CisJfQorCXJldHVybiByZXQ7 Cit9CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZmlsZV9vcGVyYXRpb25zIHVkbWFidWZfZm9wcyA9 IHsKKwkub3duZXIJCT0gVEhJU19NT0RVTEUsCisJLnVubG9ja2VkX2lvY3RsID0gdWRtYWJ1Zl9p b2N0bCwKK307CisKK3N0YXRpYyBzdHJ1Y3QgbWlzY2RldmljZSB1ZG1hYnVmX21pc2MgPSB7CisJ Lm1pbm9yICAgICAgICAgID0gTUlTQ19EWU5BTUlDX01JTk9SLAorCS5uYW1lICAgICAgICAgICA9 ICJ1ZG1hYnVmIiwKKwkuZm9wcyAgICAgICAgICAgPSAmdWRtYWJ1Zl9mb3BzLAorfTsKKworc3Rh dGljIGludCBfX2luaXQgdWRtYWJ1Zl9kZXZfaW5pdCh2b2lkKQoreworCXJldHVybiBtaXNjX3Jl Z2lzdGVyKCZ1ZG1hYnVmX21pc2MpOworfQorCitzdGF0aWMgdm9pZCBfX2V4aXQgdWRtYWJ1Zl9k ZXZfZXhpdCh2b2lkKQoreworCW1pc2NfZGVyZWdpc3RlcigmdWRtYWJ1Zl9taXNjKTsKK30KKwor bW9kdWxlX2luaXQodWRtYWJ1Zl9kZXZfaW5pdCkKK21vZHVsZV9leGl0KHVkbWFidWZfZGV2X2V4 aXQpCisKK01PRFVMRV9BVVRIT1IoIkdlcmQgSG9mZm1hbm4gPGtyYXhlbEByZWRoYXQuY29tPiIp OworTU9EVUxFX0xJQ0VOU0UoIkdQTCB2MiIpOwpkaWZmIC0tZ2l0IGEvdG9vbHMvdGVzdGluZy9z ZWxmdGVzdHMvZHJpdmVycy9kbWEtYnVmL3VkbWFidWYuYyBiL3Rvb2xzL3Rlc3Rpbmcvc2VsZnRl c3RzL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXgg MDAwMDAwMDAwMC4uMzc2YjFkNjczMAotLS0gL2Rldi9udWxsCisrKyBiL3Rvb2xzL3Rlc3Rpbmcv c2VsZnRlc3RzL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMKQEAgLTAsMCArMSw5NiBAQAorLy8g U1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKKyNpbmNsdWRlIDxzdGRpby5oPgorI2lu Y2x1ZGUgPHN0ZGxpYi5oPgorI2luY2x1ZGUgPHVuaXN0ZC5oPgorI2luY2x1ZGUgPHN0cmluZy5o PgorI2luY2x1ZGUgPGVycm5vLmg+CisjaW5jbHVkZSA8ZmNudGwuaD4KKyNpbmNsdWRlIDxtYWxs b2MuaD4KKworI2luY2x1ZGUgPHN5cy9pb2N0bC5oPgorI2luY2x1ZGUgPHN5cy9zeXNjYWxsLmg+ CisjaW5jbHVkZSA8bGludXgvbWVtZmQuaD4KKyNpbmNsdWRlIDxsaW51eC91ZG1hYnVmLmg+CisK KyNkZWZpbmUgVEVTVF9QUkVGSVgJImRyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmIgorI2RlZmluZSBO VU1fUEFHRVMgICAgICAgNAorCitzdGF0aWMgaW50IG1lbWZkX2NyZWF0ZShjb25zdCBjaGFyICpu YW1lLCB1bnNpZ25lZCBpbnQgZmxhZ3MpCit7CisJcmV0dXJuIHN5c2NhbGwoX19OUl9tZW1mZF9j cmVhdGUsIG5hbWUsIGZsYWdzKTsKK30KKworaW50IG1haW4oaW50IGFyZ2MsIGNoYXIgKmFyZ3Zb XSkKK3sKKwlzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGUgY3JlYXRlOworCWludCBkZXZmZCwgbWVtZmQs IGJ1ZiwgcmV0OworCW9mZl90IHNpemU7CisJdm9pZCAqbWVtOworCisJZGV2ZmQgPSBvcGVuKCIv ZGV2L3VkbWFidWYiLCBPX1JEV1IpOworCWlmIChkZXZmZCA8IDApIHsKKwkJcHJpbnRmKCIlczog W3NraXAsbm8tdWRtYWJ1Zl1cbiIsIFRFU1RfUFJFRklYKTsKKwkJZXhpdCg3Nyk7CisJfQorCisJ bWVtZmQgPSBtZW1mZF9jcmVhdGUoInVkbWFidWYtdGVzdCIsIE1GRF9DTE9FWEVDKTsKKwlpZiAo bWVtZmQgPCAwKSB7CisJCXByaW50ZigiJXM6IFtza2lwLG5vLW1lbWZkXVxuIiwgVEVTVF9QUkVG SVgpOworCQlleGl0KDc3KTsKKwl9CisKKwlzaXplID0gZ2V0cGFnZXNpemUoKSAqIE5VTV9QQUdF UzsKKwlyZXQgPSBmdHJ1bmNhdGUobWVtZmQsIHNpemUpOworCWlmIChyZXQgPT0gLTEpIHsKKwkJ cHJpbnRmKCIlczogW0ZBSUwsbWVtZmQtdHJ1bmNhdGVdXG4iLCBURVNUX1BSRUZJWCk7CisJCWV4 aXQoMSk7CisJfQorCisJbWVtc2V0KCZjcmVhdGUsIDAsIHNpemVvZihjcmVhdGUpKTsKKworCS8q IHNob3VsZCBmYWlsIChvZmZzZXQgbm90IHBhZ2UgYWxpZ25lZCkgKi8KKwljcmVhdGUubWVtZmQg ID0gbWVtZmQ7CisJY3JlYXRlLm9mZnNldCA9IGdldHBhZ2VzaXplKCkvMjsKKwljcmVhdGUuc2l6 ZSAgID0gZ2V0cGFnZXNpemUoKTsKKwlidWYgPSBpb2N0bChkZXZmZCwgVURNQUJVRl9DUkVBVEUs ICZjcmVhdGUpOworCWlmIChidWYgPj0gMCkgeworCQlwcmludGYoIiVzOiBbRkFJTCx0ZXN0LTFd XG4iLCBURVNUX1BSRUZJWCk7CisJCWV4aXQoMSk7CisJfQorCisJLyogc2hvdWxkIGZhaWwgKHNp emUgbm90IG11bHRpcGxlIG9mIHBhZ2UpICovCisJY3JlYXRlLm1lbWZkICA9IG1lbWZkOworCWNy ZWF0ZS5vZmZzZXQgPSAwOworCWNyZWF0ZS5zaXplICAgPSBnZXRwYWdlc2l6ZSgpLzI7CisJYnVm ID0gaW9jdGwoZGV2ZmQsIFVETUFCVUZfQ1JFQVRFLCAmY3JlYXRlKTsKKwlpZiAoYnVmID49IDAp IHsKKwkJcHJpbnRmKCIlczogW0ZBSUwsdGVzdC0yXVxuIiwgVEVTVF9QUkVGSVgpOworCQlleGl0 KDEpOworCX0KKworCS8qIHNob3VsZCBmYWlsIChub3QgbWVtZmQpICovCisJY3JlYXRlLm1lbWZk ICA9IDA7IC8qIHN0ZGluICovCisJY3JlYXRlLm9mZnNldCA9IDA7CisJY3JlYXRlLnNpemUgICA9 IHNpemU7CisJYnVmID0gaW9jdGwoZGV2ZmQsIFVETUFCVUZfQ1JFQVRFLCAmY3JlYXRlKTsKKwlp ZiAoYnVmID49IDApIHsKKwkJcHJpbnRmKCIlczogW0ZBSUwsdGVzdC0zXVxuIiwgVEVTVF9QUkVG SVgpOworCQlleGl0KDEpOworCX0KKworCS8qIHNob3VsZCB3b3JrICovCisJY3JlYXRlLm1lbWZk ICA9IG1lbWZkOworCWNyZWF0ZS5vZmZzZXQgPSAwOworCWNyZWF0ZS5zaXplICAgPSBzaXplOwor CWJ1ZiA9IGlvY3RsKGRldmZkLCBVRE1BQlVGX0NSRUFURSwgJmNyZWF0ZSk7CisJaWYgKGJ1ZiA8 IDApIHsKKwkJcHJpbnRmKCIlczogW0ZBSUwsdGVzdC00XVxuIiwgVEVTVF9QUkVGSVgpOworCQll eGl0KDEpOworCX0KKworCWZwcmludGYoc3RkZXJyLCAiJXM6IG9rXG4iLCBURVNUX1BSRUZJWCk7 CisJY2xvc2UoYnVmKTsKKwljbG9zZShtZW1mZCk7CisJY2xvc2UoZGV2ZmQpOworCXJldHVybiAw OworfQpkaWZmIC0tZ2l0IGEvTUFJTlRBSU5FUlMgYi9NQUlOVEFJTkVSUwppbmRleCAwN2QxNTc2 ZmM3Li5hOGUxYmIzYmMzIDEwMDY0NAotLS0gYS9NQUlOVEFJTkVSUworKysgYi9NQUlOVEFJTkVS UwpAQCAtMTQ2MzgsNiArMTQ2MzgsMTQgQEAgUzoJTWFpbnRhaW5lZAogRjoJRG9jdW1lbnRhdGlv bi9maWxlc3lzdGVtcy91ZGYudHh0CiBGOglmcy91ZGYvCiAKK1VETUFCVUYgRFJJVkVSCitNOglH ZXJkIEhvZmZtYW5uIDxrcmF4ZWxAcmVkaGF0LmNvbT4KK0w6CWRyaS1kZXZlbEBsaXN0cy5mcmVl ZGVza3RvcC5vcmcKK1M6CU1haW50YWluZWQKK0Y6CWRyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMK K0Y6CWluY2x1ZGUvdWFwaS9saW51eC91ZG1hYnVmLmgKK0Y6CXRvb2xzL3Rlc3Rpbmcvc2VsZnRl c3RzL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMKKwogVURSQVcgVEFCTEVUCiBNOglCYXN0aWVu IE5vY2VyYSA8aGFkZXNzQGhhZGVzcy5uZXQ+CiBMOglsaW51eC1pbnB1dEB2Z2VyLmtlcm5lbC5v cmcKZGlmZiAtLWdpdCBhL2RyaXZlcnMvZG1hLWJ1Zi9LY29uZmlnIGIvZHJpdmVycy9kbWEtYnVm L0tjb25maWcKaW5kZXggZWQzYjc4NWJhZS4uMzM4MTI5ZWIxMiAxMDA2NDQKLS0tIGEvZHJpdmVy cy9kbWEtYnVmL0tjb25maWcKKysrIGIvZHJpdmVycy9kbWEtYnVmL0tjb25maWcKQEAgLTMwLDQg KzMwLDEyIEBAIGNvbmZpZyBTV19TWU5DCiAJICBXQVJOSU5HOiBpbXByb3BlciB1c2Ugb2YgdGhp cyBjYW4gcmVzdWx0IGluIGRlYWRsb2NraW5nIGtlcm5lbAogCSAgZHJpdmVycyBmcm9tIHVzZXJz cGFjZS4gSW50ZW5kZWQgZm9yIHRlc3QgYW5kIGRlYnVnIG9ubHkuCiAKK2NvbmZpZyBVRE1BQlVG CisJYm9vbCAidXNlcnNwYWNlIGRtYWJ1ZiBtaXNjIGRyaXZlciIKKwlkZWZhdWx0IG4KKwlkZXBl bmRzIG9uIERNQV9TSEFSRURfQlVGRkVSCisJaGVscAorCSAgQSBkcml2ZXIgdG8gbGV0IHVzZXJz cGFjZSB0dXJuIG1lbWZkIHJlZ2lvbnMgaW50byBkbWEtYnVmcy4KKwkgIFFlbXUgY2FuIHVzZSB0 aGlzIHRvIGNyZWF0ZSBob3N0IGRtYWJ1ZnMgZm9yIGd1ZXN0IGZyYW1lYnVmZmVycy4KKwogZW5k bWVudQpkaWZmIC0tZ2l0IGEvZHJpdmVycy9kbWEtYnVmL01ha2VmaWxlIGIvZHJpdmVycy9kbWEt YnVmL01ha2VmaWxlCmluZGV4IGMzM2JmODg2MzEuLjA5MTNhNmNjYWIgMTAwNjQ0Ci0tLSBhL2Ry aXZlcnMvZG1hLWJ1Zi9NYWtlZmlsZQorKysgYi9kcml2ZXJzL2RtYS1idWYvTWFrZWZpbGUKQEAg LTEsMyArMSw0IEBACiBvYmoteSA6PSBkbWEtYnVmLm8gZG1hLWZlbmNlLm8gZG1hLWZlbmNlLWFy cmF5Lm8gcmVzZXJ2YXRpb24ubyBzZXFuby1mZW5jZS5vCiBvYmotJChDT05GSUdfU1lOQ19GSUxF KQkJKz0gc3luY19maWxlLm8KIG9iai0kKENPTkZJR19TV19TWU5DKQkJKz0gc3dfc3luYy5vIHN5 bmNfZGVidWcubworb2JqLSQoQ09ORklHX1VETUFCVUYpCQkrPSB1ZG1hYnVmLm8KZGlmZiAtLWdp dCBhL3Rvb2xzL3Rlc3Rpbmcvc2VsZnRlc3RzL2RyaXZlcnMvZG1hLWJ1Zi9NYWtlZmlsZSBiL3Rv b2xzL3Rlc3Rpbmcvc2VsZnRlc3RzL2RyaXZlcnMvZG1hLWJ1Zi9NYWtlZmlsZQpuZXcgZmlsZSBt b2RlIDEwMDY0NAppbmRleCAwMDAwMDAwMDAwLi40MTU0YzNkN2FhCi0tLSAvZGV2L251bGwKKysr IGIvdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9kbWEtYnVmL01ha2VmaWxlCkBAIC0w LDAgKzEsNSBAQAorQ0ZMQUdTICs9IC1JLi4vLi4vLi4vLi4vLi4vdXNyL2luY2x1ZGUvCisKK1RF U1RfR0VOX1BST0dTIDo9IHVkbWFidWYKKworaW5jbHVkZSAuLi8uLi9saWIubWsKLS0gCjIuOS4z CgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpkcmktZGV2 ZWwgbWFpbGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5mcmVlZGVza3RvcC5vcmcKaHR0cHM6Ly9s aXN0cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9kcmktZGV2ZWwK