From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752935AbcBAJTS (ORCPT ); Mon, 1 Feb 2016 04:19:18 -0500 Received: from mail-lb0-f182.google.com ([209.85.217.182]:33011 "EHLO mail-lb0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751821AbcBAJPw (ORCPT ); Mon, 1 Feb 2016 04:15:52 -0500 From: Jens Wiklander To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, Arnd Bergmann , Greg Kroah-Hartman Cc: valentin.manea@huawei.com, jean-michel.delorme@st.com, emmanuel.michel@st.com, javier@javigon.com, Jason Gunthorpe , Mark Rutland , Michal Simek , Rob Herring , Will Deacon , Jens Wiklander Subject: [PATCH v7 2/4] tee: generic TEE subsystem Date: Mon, 1 Feb 2016 10:15:38 +0100 Message-Id: <1454318140-7962-3-git-send-email-jens.wiklander@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1454318140-7962-1-git-send-email-jens.wiklander@linaro.org> References: <1454318140-7962-1-git-send-email-jens.wiklander@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Initial patch for generic TEE subsystem. This subsystem provides: * Registration/un-registration of TEE drivers. * Shared memory between normal world and secure world. * Ioctl interface for interaction with user space. * Sysfs implementation_id of TEE driver A TEE (Trusted Execution Environment) driver is a driver that interfaces with a trusted OS running in some secure environment, for example, TrustZone on ARM cpus, or a separate secure co-processor etc. The TEE subsystem can serve a TEE driver for a Global Platform compliant TEE, but it's not limited to only Global Platform TEEs. This patch builds on other similar implementations trying to solve the same problem: * "optee_linuxdriver" by among others Jean-michel DELORME and Emmanuel MICHEL * "Generic TrustZone Driver" by Javier González Signed-off-by: Jens Wiklander --- Documentation/ioctl/ioctl-number.txt | 1 + MAINTAINERS | 6 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/tee/Kconfig | 8 + drivers/tee/Makefile | 3 + drivers/tee/tee.c | 873 +++++++++++++++++++++++++++++++++++ drivers/tee/tee_private.h | 80 ++++ drivers/tee/tee_shm.c | 324 +++++++++++++ drivers/tee/tee_shm_pool.c | 133 ++++++ include/linux/tee_drv.h | 299 ++++++++++++ include/uapi/linux/tee.h | 383 +++++++++++++++ 12 files changed, 2113 insertions(+) create mode 100644 drivers/tee/Kconfig create mode 100644 drivers/tee/Makefile create mode 100644 drivers/tee/tee.c create mode 100644 drivers/tee/tee_private.h create mode 100644 drivers/tee/tee_shm.c create mode 100644 drivers/tee/tee_shm_pool.c create mode 100644 include/linux/tee_drv.h create mode 100644 include/uapi/linux/tee.h diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 91261a3..b5ce7b6 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -307,6 +307,7 @@ Code Seq#(hex) Include File Comments 0xA3 80-8F Port ACL in development: 0xA3 90-9F linux/dtlk.h +0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem 0xAA 00-3F linux/uapi/linux/userfaultfd.h 0xAB 00-1F linux/nbd.h 0xAC 00-1F linux/raw.h diff --git a/MAINTAINERS b/MAINTAINERS index 30aca4a..e3dfc81e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9566,6 +9566,12 @@ F: Documentation/trace/stm.txt F: drivers/hwtracing/stm/ F: include/linux/stm.h F: include/uapi/linux/stm.h +TEE SUBSYSTEM +M: Jens Wiklander +S: Maintained +F: include/linux/tee_drv.h +F: include/uapi/linux/tee.h +F: drivers/tee/ THUNDERBOLT DRIVER M: Andreas Noever diff --git a/drivers/Kconfig b/drivers/Kconfig index d2ac339..63baceb 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -198,4 +198,6 @@ source "drivers/hwtracing/intel_th/Kconfig" source "drivers/fpga/Kconfig" +source "drivers/tee/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 8f5d076..231b409 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -172,3 +172,4 @@ obj-$(CONFIG_STM) += hwtracing/stm/ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_NVMEM) += nvmem/ obj-$(CONFIG_FPGA) += fpga/ +obj-$(CONFIG_TEE) += tee/ diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig new file mode 100644 index 0000000..64a8cd7 --- /dev/null +++ b/drivers/tee/Kconfig @@ -0,0 +1,8 @@ +# Generic Trusted Execution Environment Configuration +config TEE + bool "Trusted Execution Environment support" + default n + select DMA_SHARED_BUFFER + help + This implements a generic interface towards a Trusted Execution + Environment (TEE). diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile new file mode 100644 index 0000000..60d2dab --- /dev/null +++ b/drivers/tee/Makefile @@ -0,0 +1,3 @@ +obj-y += tee.o +obj-y += tee_shm.o +obj-y += tee_shm_pool.o diff --git a/drivers/tee/tee.c b/drivers/tee/tee.c new file mode 100644 index 0000000..b8a1c76 --- /dev/null +++ b/drivers/tee/tee.c @@ -0,0 +1,873 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include "tee_private.h" + +#define TEE_NUM_DEVICES 32 + +#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x)) + +/* + * Unprivileged devices in the in the lower half range and privileged + * devices in the upper half range. + */ +static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES); +static DEFINE_SPINLOCK(driver_lock); + +static struct class *tee_class; +static dev_t tee_devt; + +static int tee_open(struct inode *inode, struct file *filp) +{ + int rc; + struct tee_device *teedev; + struct tee_context *ctx; + + teedev = container_of(inode->i_cdev, struct tee_device, cdev); + if (!tee_device_get(teedev)) + return -EINVAL; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + rc = -ENOMEM; + goto err; + } + + ctx->teedev = teedev; + filp->private_data = ctx; + rc = teedev->desc->ops->open(ctx); + if (rc) + goto err; + + return 0; +err: + kfree(ctx); + tee_device_put(teedev); + return rc; +} + +static int tee_release(struct inode *inode, struct file *filp) +{ + struct tee_context *ctx = filp->private_data; + struct tee_device *teedev = ctx->teedev; + + ctx->teedev->desc->ops->release(ctx); + kfree(ctx); + tee_device_put(teedev); + return 0; +} + +static int tee_ioctl_version(struct tee_context *ctx, + struct tee_ioctl_version_data __user *uvers) +{ + struct tee_ioctl_version_data vers; + + ctx->teedev->desc->ops->get_version(ctx->teedev, &vers); + if (copy_to_user(uvers, &vers, sizeof(vers))) + return -EFAULT; + return 0; +} + +static int tee_ioctl_shm_alloc(struct tee_context *ctx, + struct tee_ioctl_shm_alloc_data __user *udata) +{ + long ret; + struct tee_ioctl_shm_alloc_data data; + struct tee_shm *shm; + + if (copy_from_user(&data, udata, sizeof(data))) + return -EFAULT; + + /* Currently no input flags are supported */ + if (data.flags) + return -EINVAL; + + data.fd = -1; + + shm = tee_shm_alloc(ctx->teedev, data.size, + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + data.flags = shm->flags; + data.size = shm->size; + data.fd = tee_shm_get_fd(shm); + if (data.fd < 0) { + ret = data.fd; + goto err; + } + + if (copy_to_user(udata, &data, sizeof(data))) { + ret = -EFAULT; + goto err; + } + /* + * When user space closes the file descriptor the shared memory + * should be freed + */ + tee_shm_put(shm); + return 0; +err: + if (data.fd >= 0) + tee_shm_put_fd(data.fd); + tee_shm_free(shm); + return ret; +} + +static int params_from_user(struct tee_param *params, size_t num_params, + struct tee_ioctl_param __user *uparams) +{ + size_t n; + + for (n = 0; n < num_params; n++) { + struct tee_shm *shm; + struct tee_ioctl_param ip; + + if (copy_from_user(&ip, uparams + n, sizeof(ip))) + return -EFAULT; + + /* All unused attribute bits has to be zero */ + if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK) + return -EINVAL; + + params[n].attr = ip.attr; + switch (ip.attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + params[n].u.value.a = ip.u.value.a; + params[n].u.value.b = ip.u.value.b; + params[n].u.value.c = ip.u.value.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + /* + * If we fail to get a pointer to a shared memory + * object (and increase the ref count) from a file + * descriptor we return an error. All pointers that + * has been added in params have an increased ref + * count. It's the callers responibility to do + * tee_shm_put() on all resolved pointers. + */ + shm = tee_shm_get_from_fd(ip.u.memref.shm_fd); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + params[n].u.memref.shm_offs = ip.u.memref.shm_offs; + params[n].u.memref.size = ip.u.memref.size; + params[n].u.memref.shm = shm; + break; + default: + /* Unknown attribute */ + return -EINVAL; + } + } + return 0; +} + +static int params_to_user(struct tee_ioctl_param __user *uparams, + size_t num_params, struct tee_param *params) +{ + size_t n; + + for (n = 0; n < num_params; n++) { + struct tee_ioctl_param __user *up = uparams + n; + struct tee_param *p = params + n; + + switch (p->attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + if (put_user(p->u.value.a, &up->u.value.a) || + put_user(p->u.value.b, &up->u.value.b) || + put_user(p->u.value.c, &up->u.value.c)) + return -EFAULT; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + if (put_user((u64)p->u.memref.size, &up->u.memref.size)) + return -EFAULT; + default: + break; + } + } + return 0; +} + +static bool param_is_memref(struct tee_param *param) +{ + switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + return true; + default: + return false; + } +} + +static int tee_ioctl_open_session(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + int rc; + size_t n; + struct tee_ioctl_buf_data buf; + struct tee_ioctl_open_session_arg __user *uarg; + struct tee_ioctl_open_session_arg arg; + struct tee_ioctl_param __user *uparams = NULL; + struct tee_param *params = NULL; + bool have_session = false; + + if (!ctx->teedev->desc->ops->open_session) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_ioctl_open_session_arg)) + return -EINVAL; + + uarg = (struct tee_ioctl_open_session_arg __user *)(unsigned long) + buf.buf_ptr; + rc = copy_from_user(&arg, uarg, sizeof(arg)); + if (rc) + return rc; + + if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) + return -EINVAL; + + if (arg.num_params) { + params = kcalloc(arg.num_params, sizeof(struct tee_param), + GFP_KERNEL); + if (!params) + return -ENOMEM; + uparams = (struct tee_ioctl_param __user *)(uarg + 1); + rc = params_from_user(params, arg.num_params, uparams); + if (rc) + goto out; + } + + rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params); + if (rc) + goto out; + have_session = true; + + if (put_user(arg.session, &uarg->session) || + put_user(arg.ret, &uarg->ret) || + put_user(arg.ret_origin, &uarg->ret_origin)) { + rc = -EFAULT; + goto out; + } + rc = params_to_user(uparams, arg.num_params, params); +out: + /* + * If we've succeeded to open the session but failed to communicate + * it back to user space, close the session again to avoid leakage. + */ + if (rc && have_session && ctx->teedev->desc->ops->close_session) + ctx->teedev->desc->ops->close_session(ctx, arg.session); + + if (params) { + /* Decrease ref count for all valid shared memory pointers */ + for (n = 0; n < arg.num_params; n++) + if (param_is_memref(params + n) && + params[n].u.memref.shm) + tee_shm_put(params[n].u.memref.shm); + kfree(params); + } + + return rc; +} + +static int tee_ioctl_invoke(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + int rc; + size_t n; + struct tee_ioctl_buf_data buf; + struct tee_ioctl_invoke_arg __user *uarg; + struct tee_ioctl_invoke_arg arg; + struct tee_ioctl_param __user *uparams = NULL; + struct tee_param *params = NULL; + + if (!ctx->teedev->desc->ops->invoke_func) + return -EINVAL; + + rc = copy_from_user(&buf, ubuf, sizeof(buf)); + if (rc) + return rc; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_ioctl_invoke_arg)) + return -EINVAL; + + uarg = (struct tee_ioctl_invoke_arg __user *)(unsigned long)buf.buf_ptr; + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) + return -EINVAL; + + if (arg.num_params) { + params = kcalloc(arg.num_params, sizeof(struct tee_param), + GFP_KERNEL); + if (!params) + return -ENOMEM; + uparams = (struct tee_ioctl_param __user *)(uarg + 1); + rc = params_from_user(params, arg.num_params, uparams); + if (rc) + goto out; + } + + rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params); + if (rc) + goto out; + + if (put_user(arg.ret, &uarg->ret) || + put_user(arg.ret_origin, &uarg->ret_origin)) { + rc = -EFAULT; + goto out; + } + rc = params_to_user(uparams, arg.num_params, params); +out: + if (params) { + /* Decrease ref count for all valid shared memory pointers */ + for (n = 0; n < arg.num_params; n++) + if (param_is_memref(params + n) && + params[n].u.memref.shm) + tee_shm_put(params[n].u.memref.shm); + kfree(params); + } + return rc; +} + + +static int tee_ioctl_cancel(struct tee_context *ctx, + struct tee_ioctl_cancel_arg __user *uarg) +{ + struct tee_ioctl_cancel_arg arg; + + if (!ctx->teedev->desc->ops->cancel_req) + return -EINVAL; + + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + return ctx->teedev->desc->ops->cancel_req(ctx, arg.cancel_id, + arg.session); +} + +static int tee_ioctl_close_session(struct tee_context *ctx, + struct tee_ioctl_close_session_arg __user *uarg) +{ + struct tee_ioctl_close_session_arg arg; + + if (!ctx->teedev->desc->ops->close_session) + return -EINVAL; + + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + return ctx->teedev->desc->ops->close_session(ctx, arg.session); +} + +static int params_to_supp(struct tee_ioctl_param __user *uparams, + size_t num_params, struct tee_param *params) +{ + int rc = 0; + size_t n; + int *fds = kmalloc_array(num_params, sizeof(int), GFP_KERNEL); + + if (!fds) + return -ENOMEM; + for (n = 0; n < num_params; n++) + fds[n] = -1; + + for (n = 0; n < num_params; n++) { + struct tee_ioctl_param ip; + struct tee_param *p = params + n; + + ip.attr = p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK; + switch (p->attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + ip.u.value.a = p->u.value.a; + ip.u.value.b = p->u.value.b; + ip.u.value.c = p->u.value.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + ip.u.memref.size = p->u.memref.size; + if (!p->u.memref.shm) { + ip.u.memref.shm_offs = 0; + ip.u.memref.shm_fd = -1; + break; + } + ip.u.memref.shm_offs = p->u.memref.shm_offs; + /* + * This tee_shm_get_fd() is supposed to be matched + * by a close(2) from tee-supplicant. + */ + fds[n] = tee_shm_get_fd(p->u.memref.shm); + if (fds[n] < 0) { + rc = fds[n]; + goto out; + } + ip.u.memref.shm_fd = fds[n]; + break; + default: + memset(&ip.u, 0, sizeof(ip.u)); + break; + } + + if (copy_to_user(uparams + n, &ip, sizeof(ip))) { + rc = -EFAULT; + goto out; + } + } +out: + if (rc) { + for (n = 0; n < num_params; n++) + if (fds[n] >= 0) + tee_shm_put_fd(fds[n]); + } + kfree(fds); + return rc; +} + +static int tee_ioctl_supp_recv(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + int rc; + struct tee_ioctl_buf_data buf; + struct tee_iocl_supp_recv_arg __user *uarg; + struct tee_param *params; + struct tee_ioctl_param __user *uparams; + u32 num_params; + u32 func; + + if (!ctx->teedev->desc->ops->supp_recv) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_iocl_supp_recv_arg)) + return -EINVAL; + + uarg = (struct tee_iocl_supp_recv_arg __user *)(unsigned long) + buf.buf_ptr; + if (get_user(num_params, &uarg->num_params)) + return -EFAULT; + + if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) != buf.buf_len) + return -EINVAL; + + params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); + if (!params) + return -ENOMEM; + + rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params); + if (rc) + goto out; + + if (put_user(func, &uarg->func) || + put_user(num_params, &uarg->num_params)) { + rc = -EFAULT; + goto out; + } + + uparams = (struct tee_ioctl_param __user *)(uarg + 1); + rc = params_to_supp(uparams, num_params, params); +out: + kfree(params); + return rc; +} + +static int params_from_supp(struct tee_param *params, + size_t num_params, struct tee_ioctl_param __user *uparams) +{ + size_t n; + + for (n = 0; n < num_params; n++) { + struct tee_param *p = params + n; + struct tee_ioctl_param ip; + + if (copy_from_user(&ip, uparams + n, sizeof(ip))) + return -EFAULT; + + /* All unused attribute bits has to be zero */ + if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK) + return -EINVAL; + + p->attr = ip.attr; + switch (ip.attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + /* Only out and in/out values can be updated */ + p->u.value.a = ip.u.value.a; + p->u.value.b = ip.u.value.b; + p->u.value.c = ip.u.value.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + /* + * Only the size of the memref can be updated. + * Since we don't have access to the original + * parameters here, only store the supplied size. + * The driver will copy the updated size into the + * original parameters. + */ + p->u.memref.shm = NULL; + p->u.memref.shm_offs = 0; + p->u.memref.size = ip.u.memref.size; + break; + default: + memset(&p->u, 0, sizeof(p->u)); + break; + } + } + return 0; +} + +static int tee_ioctl_supp_send(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + long rc; + struct tee_ioctl_buf_data buf; + struct tee_iocl_supp_send_arg __user *uarg; + struct tee_param *params; + struct tee_ioctl_param __user *uparams; + u32 num_params; + u32 ret; + + /* Not valid for this driver */ + if (!ctx->teedev->desc->ops->supp_send) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_iocl_supp_send_arg)) + return -EINVAL; + + uarg = (struct tee_iocl_supp_send_arg __user *)(unsigned long) + buf.buf_ptr; + if (get_user(ret, &uarg->ret) || + get_user(num_params, &uarg->num_params)) + return -EFAULT; + + if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) > buf.buf_len) + return -EINVAL; + + params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); + if (!params) + return -ENOMEM; + + uparams = (struct tee_ioctl_param __user *)(uarg + 1); + rc = params_from_supp(params, num_params, uparams); + if (rc) + goto out; + + rc = ctx->teedev->desc->ops->supp_send(ctx, ret, num_params, params); +out: + kfree(params); + return rc; +} + + +static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct tee_context *ctx = filp->private_data; + void __user *uarg = (void __user *)arg; + + switch (cmd) { + case TEE_IOC_VERSION: + return tee_ioctl_version(ctx, uarg); + case TEE_IOC_SHM_ALLOC: + return tee_ioctl_shm_alloc(ctx, uarg); + case TEE_IOC_OPEN_SESSION: + return tee_ioctl_open_session(ctx, uarg); + case TEE_IOC_INVOKE: + return tee_ioctl_invoke(ctx, uarg); + case TEE_IOC_CANCEL: + return tee_ioctl_cancel(ctx, uarg); + case TEE_IOC_CLOSE_SESSION: + return tee_ioctl_close_session(ctx, uarg); + case TEE_IOC_SUPPL_RECV: + return tee_ioctl_supp_recv(ctx, uarg); + case TEE_IOC_SUPPL_SEND: + return tee_ioctl_supp_send(ctx, uarg); + default: + return -EINVAL; + } +} + +static const struct file_operations tee_fops = { + .open = tee_open, + .release = tee_release, + .unlocked_ioctl = tee_ioctl, + .compat_ioctl = tee_ioctl, +}; + +static void tee_release_device(struct device *dev) +{ + struct tee_device *teedev = container_of(dev, struct tee_device, dev); + + spin_lock(&driver_lock); + clear_bit(teedev->id, dev_mask); + spin_unlock(&driver_lock); + mutex_destroy(&teedev->mutex); + kfree(teedev); +} + +struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, + struct device *dev, struct tee_shm_pool *pool, + void *driver_data) +{ + struct tee_device *teedev; + void *ret; + int rc; + int offs = 0; + + if (!teedesc || !teedesc->name || !teedesc->ops || + !teedesc->ops->get_version || !teedesc->ops->open || + !teedesc->ops->release || !dev || !pool) + return ERR_PTR(-EINVAL); + + teedev = kzalloc(sizeof(*teedev), GFP_KERNEL); + if (!teedev) { + ret = ERR_PTR(-ENOMEM); + goto err; + } + + if (teedesc->flags & TEE_DESC_PRIVILEGED) + offs = TEE_NUM_DEVICES / 2; + + spin_lock(&driver_lock); + teedev->id = find_next_zero_bit(dev_mask, TEE_NUM_DEVICES, offs); + if (teedev->id < TEE_NUM_DEVICES) + set_bit(teedev->id, dev_mask); + spin_unlock(&driver_lock); + + if (teedev->id >= TEE_NUM_DEVICES) { + ret = ERR_PTR(-ENOMEM); + goto err; + } + + snprintf(teedev->name, sizeof(teedev->name), "tee%s%d", + teedesc->flags & TEE_DESC_PRIVILEGED ? "priv" : "", + teedev->id - offs); + + teedev->dev.class = tee_class; + teedev->dev.release = tee_release_device; + teedev->dev.parent = dev; + teedev->dev.devt = MKDEV(MAJOR(tee_devt), teedev->id); + + rc = dev_set_name(&teedev->dev, "%s", teedev->name); + if (rc) { + ret = ERR_PTR(rc); + goto err; + } + + cdev_init(&teedev->cdev, &tee_fops); + teedev->cdev.owner = teedesc->owner; + teedev->cdev.kobj.parent = &teedev->dev.kobj; + + dev_set_drvdata(&teedev->dev, driver_data); + device_initialize(&teedev->dev); + + /* 1 as tee_device_unregister() does one final tee_device_put() */ + teedev->num_users = 1; + init_completion(&teedev->c_no_users); + mutex_init(&teedev->mutex); + + teedev->desc = teedesc; + teedev->pool = pool; + INIT_LIST_HEAD(&teedev->list_shm); + + return teedev; +err: + dev_err(dev, "could not register %s driver\n", + teedesc->flags & TEE_DESC_PRIVILEGED ? "privileged" : "client"); + if (teedev && teedev->id < TEE_NUM_DEVICES) { + spin_lock(&driver_lock); + clear_bit(teedev->id, dev_mask); + spin_unlock(&driver_lock); + } + kfree(teedev); + return ret; +} +EXPORT_SYMBOL_GPL(tee_device_alloc); + +static ssize_t implementation_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tee_device *teedev = container_of(dev, struct tee_device, dev); + struct tee_ioctl_version_data vers; + + teedev->desc->ops->get_version(teedev, &vers); + return scnprintf(buf, PAGE_SIZE, "%d\n", vers.impl_id); +} +static DEVICE_ATTR_RO(implementation_id); + +static struct attribute *tee_dev_attrs[] = { + &dev_attr_implementation_id.attr, + NULL +}; + +static const struct attribute_group tee_dev_group = { + .attrs = tee_dev_attrs, +}; + +int tee_device_register(struct tee_device *teedev) +{ + int rc; + + /* + * If the teedev already is registered, don't do it again. It's + * obviously an error to try to register twice, but if we return + * an error we'll force the driver to remove the teedev. + */ + if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { + dev_err(&teedev->dev, "attempt to register twice\n"); + return 0; + } + + rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1); + if (rc) { + dev_err(&teedev->dev, + "unable to cdev_add() %s, major %d, minor %d, err=%d\n", + teedev->name, MAJOR(teedev->dev.devt), + MINOR(teedev->dev.devt), rc); + return rc; + } + + rc = device_add(&teedev->dev); + if (rc) { + dev_err(&teedev->dev, + "unable to device_add() %s, major %d, minor %d, err=%d\n", + teedev->name, MAJOR(teedev->dev.devt), + MINOR(teedev->dev.devt), rc); + goto err_device_add; + } + + rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group); + if (rc) { + dev_err(&teedev->dev, + "failed to create sysfs attributes, err=%d\n", rc); + goto err_sysfs_create_group; + } + + teedev->flags |= TEE_DEVICE_FLAG_REGISTERED; + return 0; + +err_sysfs_create_group: + device_del(&teedev->dev); +err_device_add: + cdev_del(&teedev->cdev); + return rc; + +} +EXPORT_SYMBOL_GPL(tee_device_register); + +void tee_device_put(struct tee_device *teedev) +{ + mutex_lock(&teedev->mutex); + /* Shouldn't put in this state */ + if (!WARN_ON(!teedev->desc)) { + teedev->num_users--; + if (!teedev->num_users) { + teedev->desc = NULL; + complete(&teedev->c_no_users); + } + } + mutex_unlock(&teedev->mutex); +} + +bool tee_device_get(struct tee_device *teedev) +{ + mutex_lock(&teedev->mutex); + if (!teedev->desc) { + mutex_unlock(&teedev->mutex); + return false; + } + teedev->num_users++; + mutex_unlock(&teedev->mutex); + return true; +} + +void tee_device_unregister(struct tee_device *teedev) +{ + if (!teedev) + return; + + if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { + sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group); + cdev_del(&teedev->cdev); + device_del(&teedev->dev); + } + + tee_device_put(teedev); + wait_for_completion(&teedev->c_no_users); + + /* + * No need to take a mutex any longer now since teedev->desc was + * set to NULL before teedev->c_no_users was completed. + */ + + teedev->pool = NULL; + + put_device(&teedev->dev); +} +EXPORT_SYMBOL_GPL(tee_device_unregister); + +void *tee_get_drvdata(struct tee_device *teedev) +{ + return dev_get_drvdata(&teedev->dev); +} +EXPORT_SYMBOL_GPL(tee_get_drvdata); + +static int __init tee_init(void) +{ + int rc; + + tee_class = class_create(THIS_MODULE, "tee"); + if (IS_ERR(tee_class)) { + pr_err("couldn't create class\n"); + return PTR_ERR(tee_class); + } + + rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee"); + if (rc < 0) { + pr_err("failed to allocate char dev region\n"); + class_destroy(tee_class); + tee_class = NULL; + } + + return rc; +} + +subsys_initcall(tee_init); diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h new file mode 100644 index 0000000..d32ac54 --- /dev/null +++ b/drivers/tee/tee_private.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef TEE_PRIVATE_H +#define TEE_PRIVATE_H + +#include +#include +#include +#include +#include +#include + +struct tee_device; + +struct tee_shm { + struct list_head list_node; + struct tee_device *teedev; + phys_addr_t paddr; + void *kaddr; + size_t size; + struct dma_buf *dmabuf; + u32 flags; +}; + +struct tee_shm_pool_mgr; +struct tee_shm_pool_mgr_ops { + int (*alloc)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm, + size_t size); + void (*free)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm); +}; + +struct tee_shm_pool_mgr { + const struct tee_shm_pool_mgr_ops *ops; + void *private_data; +}; + +struct tee_shm_pool { + struct tee_shm_pool_mgr private_mgr; + struct tee_shm_pool_mgr dma_buf_mgr; + void (*destroy)(struct tee_shm_pool *pool); + void *private_data; +}; + +#define TEE_DEVICE_FLAG_REGISTERED 0x1 +#define TEE_MAX_DEV_NAME_LEN 32 + +struct tee_device { + char name[TEE_MAX_DEV_NAME_LEN]; + const struct tee_desc *desc; + int id; + unsigned flags; + + struct device dev; + struct cdev cdev; + + size_t num_users; + struct completion c_no_users; + struct mutex mutex; + + struct list_head list_shm; + struct tee_shm_pool *pool; +}; + +int tee_shm_init(void); + +bool tee_device_get(struct tee_device *teedev); +void tee_device_put(struct tee_device *teedev); + +#endif /*TEE_PRIVATE_H*/ diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c new file mode 100644 index 0000000..6732e77 --- /dev/null +++ b/drivers/tee/tee_shm.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include "tee_private.h" + +static void tee_shm_release(struct tee_shm *shm) +{ + struct tee_device *teedev = shm->teedev; + struct tee_shm_pool_mgr *poolm; + + mutex_lock(&teedev->mutex); + list_del(&shm->list_node); + mutex_unlock(&teedev->mutex); + + if (shm->flags & TEE_SHM_DMA_BUF) + poolm = &teedev->pool->dma_buf_mgr; + else + poolm = &teedev->pool->private_mgr; + + poolm->ops->free(poolm, shm); + kfree(shm); + + tee_device_put(teedev); +} + +static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment + *attach, enum dma_data_direction dir) +{ + return NULL; +} + +static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach, + struct sg_table *table, enum dma_data_direction dir) +{ +} + +static void tee_shm_op_release(struct dma_buf *dmabuf) +{ + struct tee_shm *shm = dmabuf->priv; + + tee_shm_release(shm); +} + +static void *tee_shm_op_kmap_atomic(struct dma_buf *dmabuf, + unsigned long pgnum) +{ + return NULL; +} + +static void *tee_shm_op_kmap(struct dma_buf *dmabuf, unsigned long pgnum) +{ + return NULL; +} + +static int tee_shm_op_mmap(struct dma_buf *dmabuf, + struct vm_area_struct *vma) +{ + struct tee_shm *shm = dmabuf->priv; + size_t size = vma->vm_end - vma->vm_start; + + return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT, + size, vma->vm_page_prot); +} + +static struct dma_buf_ops tee_shm_dma_buf_ops = { + .map_dma_buf = tee_shm_op_map_dma_buf, + .unmap_dma_buf = tee_shm_op_unmap_dma_buf, + .release = tee_shm_op_release, + .kmap_atomic = tee_shm_op_kmap_atomic, + .kmap = tee_shm_op_kmap, + .mmap = tee_shm_op_mmap, +}; + +struct tee_shm *tee_shm_alloc(struct tee_device *teedev, size_t size, + u32 flags) +{ + struct tee_shm_pool_mgr *poolm = NULL; + struct tee_shm *shm; + void *ret; + int rc; + + if (!(flags & TEE_SHM_MAPPED)) { + dev_err(teedev->dev.parent, + "only mapped allocations supported\n"); + return ERR_PTR(-EINVAL); + } + + if ((flags & ~(TEE_SHM_MAPPED|TEE_SHM_DMA_BUF))) { + dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags); + return ERR_PTR(-EINVAL); + } + + if (!tee_device_get(teedev)) + return ERR_PTR(-EINVAL); + + if (!teedev->pool) { + /* teedev has been detached from driver */ + ret = ERR_PTR(-EINVAL); + goto err; + } + + shm = kzalloc(sizeof(struct tee_shm), GFP_KERNEL); + if (!shm) { + ret = ERR_PTR(-ENOMEM); + goto err; + } + + shm->flags = flags; + shm->teedev = teedev; + if (flags & TEE_SHM_DMA_BUF) + poolm = &teedev->pool->dma_buf_mgr; + else + poolm = &teedev->pool->private_mgr; + + rc = poolm->ops->alloc(poolm, shm, size); + if (rc) { + ret = ERR_PTR(rc); + goto err; + } + + mutex_lock(&teedev->mutex); + list_add_tail(&shm->list_node, &teedev->list_shm); + mutex_unlock(&teedev->mutex); + + if (flags & TEE_SHM_DMA_BUF) { + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &tee_shm_dma_buf_ops; + exp_info.size = shm->size; + exp_info.flags = O_RDWR; + exp_info.priv = shm; + + shm->dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(shm->dmabuf)) { + ret = ERR_CAST(shm->dmabuf); + goto err; + } + } + + return shm; +err: + if (poolm && shm && shm->kaddr) + poolm->ops->free(poolm, shm); + kfree(shm); + tee_device_put(teedev); + return ret; +} +EXPORT_SYMBOL_GPL(tee_shm_alloc); + +int tee_shm_get_fd(struct tee_shm *shm) +{ + u32 req_flags = TEE_SHM_MAPPED | TEE_SHM_DMA_BUF; + int fd; + + if ((shm->flags & req_flags) != req_flags) + return -EINVAL; + + fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC); + if (fd >= 0) + get_dma_buf(shm->dmabuf); + return fd; +} +EXPORT_SYMBOL_GPL(tee_shm_get_fd); + +int tee_shm_put_fd(int fd) +{ + return __close_fd(current->files, fd); +} +EXPORT_SYMBOL_GPL(tee_shm_put_fd); + +void tee_shm_free(struct tee_shm *shm) +{ + + /* + * dma_buf_put() decreases the dmabuf reference counter and will + * call tee_shm_release() when the last reference is gone. + * + * In the case of driver private memory we call tee_shm_release + * directly instead as it doesn't have a reference counter. + */ + if (shm->flags & TEE_SHM_DMA_BUF) + dma_buf_put(shm->dmabuf); + else + tee_shm_release(shm); +} +EXPORT_SYMBOL_GPL(tee_shm_free); + +static bool cmp_key_va(struct tee_shm *shm, uintptr_t va) +{ + uintptr_t shm_va = (uintptr_t)shm->kaddr; + + return (va >= shm_va) && (va < (shm_va + shm->size)); +} + +static bool cmp_key_pa(struct tee_shm *shm, uintptr_t pa) +{ + return (pa >= shm->paddr) && (pa < (shm->paddr + shm->size)); +} + +static struct tee_shm *tee_shm_find_by_key(struct tee_device *teedev, u32 flags, + bool (*cmp)(struct tee_shm *shm, uintptr_t key), + uintptr_t key) +{ + struct tee_shm *ret = NULL; + struct tee_shm *shm; + + mutex_lock(&teedev->mutex); + list_for_each_entry(shm, &teedev->list_shm, list_node) { + if (cmp(shm, key)) { + ret = shm; + break; + } + } + mutex_unlock(&teedev->mutex); + + return ret; +} + +struct tee_shm *tee_shm_find_by_va(struct tee_device *teedev, u32 flags, + void *va) +{ + return tee_shm_find_by_key(teedev, flags, cmp_key_va, (uintptr_t)va); +} +EXPORT_SYMBOL_GPL(tee_shm_find_by_va); + +struct tee_shm *tee_shm_find_by_pa(struct tee_device *teedev, u32 flags, + phys_addr_t pa) +{ + return tee_shm_find_by_key(teedev, flags, cmp_key_pa, pa); +} +EXPORT_SYMBOL_GPL(tee_shm_find_by_pa); + +int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa) +{ + /* Check that we're in the range of the shm */ + if ((char *)va < (char *)shm->kaddr) + return -EINVAL; + if ((char *)va >= ((char *)shm->kaddr + shm->size)) + return -EINVAL; + + return tee_shm_get_pa( + shm, (unsigned long)va - (unsigned long)shm->kaddr, pa); +} +EXPORT_SYMBOL_GPL(tee_shm_va2pa); + +int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va) +{ + /* Check that we're in the range of the shm */ + if (pa < shm->paddr) + return -EINVAL; + if (pa >= (shm->paddr + shm->size)) + return -EINVAL; + + if (va) { + void *v = tee_shm_get_va(shm, pa - shm->paddr); + + if (IS_ERR(v)) + return PTR_ERR(v); + *va = v; + } + return 0; +} +EXPORT_SYMBOL_GPL(tee_shm_pa2va); + +void *tee_shm_get_va(struct tee_shm *shm, size_t offs) +{ + if (offs >= shm->size) + return ERR_PTR(-EINVAL); + return (char *)shm->kaddr + offs; +} +EXPORT_SYMBOL_GPL(tee_shm_get_va); + +int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa) +{ + if (offs >= shm->size) + return -EINVAL; + if (pa) + *pa = shm->paddr + offs; + return 0; +} +EXPORT_SYMBOL_GPL(tee_shm_get_pa); + +static bool is_shm_dma_buf(struct dma_buf *dmabuf) +{ + return dmabuf->ops == &tee_shm_dma_buf_ops; +} + +struct tee_shm *tee_shm_get_from_fd(int fd) +{ + struct dma_buf *dmabuf = dma_buf_get(fd); + + if (IS_ERR(dmabuf)) + return ERR_CAST(dmabuf); + + if (!is_shm_dma_buf(dmabuf)) { + dma_buf_put(dmabuf); + return ERR_PTR(-EINVAL); + } + return dmabuf->priv; +} +EXPORT_SYMBOL_GPL(tee_shm_get_from_fd); + +void tee_shm_put(struct tee_shm *shm) +{ + if (shm->flags & TEE_SHM_DMA_BUF) + dma_buf_put(shm->dmabuf); +} +EXPORT_SYMBOL_GPL(tee_shm_put); diff --git a/drivers/tee/tee_shm_pool.c b/drivers/tee/tee_shm_pool.c new file mode 100644 index 0000000..2ef22bc --- /dev/null +++ b/drivers/tee/tee_shm_pool.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include "tee_private.h" + +static int pool_op_gen_alloc(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm, size_t size) +{ + unsigned long va; + struct gen_pool *genpool = poolm->private_data; + size_t s = roundup(size, 1 << genpool->min_alloc_order); + + va = gen_pool_alloc(genpool, s); + if (!va) + return -ENOMEM; + shm->kaddr = (void *)va; + shm->paddr = gen_pool_virt_to_phys(genpool, va); + shm->size = s; + return 0; +} + +static void pool_op_gen_free(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm) +{ + gen_pool_free(poolm->private_data, (unsigned long)shm->kaddr, + shm->size); + shm->kaddr = NULL; +} + +static const struct tee_shm_pool_mgr_ops pool_ops_generic = { + .alloc = pool_op_gen_alloc, + .free = pool_op_gen_free, +}; + +static void pool_res_mem_destroy(struct tee_shm_pool *pool) +{ + gen_pool_destroy(pool->private_mgr.private_data); + gen_pool_destroy(pool->dma_buf_mgr.private_data); +} + +static int pool_res_mem_mgr_init(struct tee_shm_pool_mgr *mgr, + struct tee_shm_pool_mem_info *info, int min_alloc_order) +{ + size_t page_mask = PAGE_SIZE - 1; + struct gen_pool *genpool = NULL; + int rc; + + /* + * Start and end must be page aligned + */ + if ((info->vaddr & page_mask) || (info->paddr & page_mask) || + (info->size & page_mask)) + return -EINVAL; + + genpool = gen_pool_create(min_alloc_order, -1); + if (!genpool) + return -ENOMEM; + + gen_pool_set_algo(genpool, gen_pool_best_fit, NULL); + rc = gen_pool_add_virt(genpool, info->vaddr, info->paddr, info->size, + -1); + if (rc) { + gen_pool_destroy(genpool); + return rc; + } + + mgr->private_data = genpool; + mgr->ops = &pool_ops_generic; + return 0; +} + +struct tee_shm_pool *tee_shm_pool_alloc_res_mem(struct device *dev, + struct tee_shm_pool_mem_info *priv_info, + struct tee_shm_pool_mem_info *dmabuf_info) +{ + struct tee_shm_pool *pool = NULL; + int ret; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) { + ret = -ENOMEM; + goto err; + } + + /* + * Create the pool for driver private shared memory + */ + ret = pool_res_mem_mgr_init(&pool->private_mgr, priv_info, + 3 /* 8 byte aligned */); + if (ret) + goto err; + + /* + * Create the pool for dma_buf shared memory + */ + ret = pool_res_mem_mgr_init(&pool->dma_buf_mgr, dmabuf_info, + PAGE_SHIFT); + if (ret) + goto err; + + pool->destroy = pool_res_mem_destroy; + return pool; +err: + if (ret == -ENOMEM) + dev_err(dev, "can't allocate memory for res_mem shared memory pool\n"); + if (pool && pool->private_mgr.private_data) + gen_pool_destroy(pool->private_mgr.private_data); + kfree(pool); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem); + +void tee_shm_pool_free(struct tee_shm_pool *pool) +{ + pool->destroy(pool); + kfree(pool); +} +EXPORT_SYMBOL_GPL(tee_shm_pool_free); diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h new file mode 100644 index 0000000..06cffa6 --- /dev/null +++ b/include/linux/tee_drv.h @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __TEE_DRV_H +#define __TEE_DRV_H + +#include +#include +#include + +/* + * The file describes the API provided by the generic TEE driver to the + * specific TEE driver. + */ + +#define TEE_SHM_MAPPED 0x1 /* Memory mapped by the kernel */ +#define TEE_SHM_DMA_BUF 0x2 /* Memory with dma-buf handle */ + +struct tee_device; +struct tee_shm; +struct tee_shm_pool; + +/** + * struct tee_context - driver specific context on file pointer data + * @teedev: pointer to this drivers struct tee_device + * @data: driver specific context data, managed by the driver + */ +struct tee_context { + struct tee_device *teedev; + void *data; +}; + +struct tee_param_memref { + size_t shm_offs; + size_t size; + struct tee_shm *shm; +}; + +struct tee_param_value { + u64 a; + u64 b; + u64 c; +}; + +struct tee_param { + u64 attr; + union { + struct tee_param_memref memref; + struct tee_param_value value; + } u; +}; + +/** + * struct tee_driver_ops - driver operations vtable + * @get_version: returns version of driver + * @open: called when the device file is opened + * @release: release this open file + */ +struct tee_driver_ops { + void (*get_version)(struct tee_device *teedev, + struct tee_ioctl_version_data *vers); + int (*open)(struct tee_context *ctx); + void (*release)(struct tee_context *ctx); + int (*open_session)(struct tee_context *ctx, + struct tee_ioctl_open_session_arg *arg, + struct tee_param *param); + int (*close_session)(struct tee_context *ctx, u32 session); + int (*invoke_func)(struct tee_context *ctx, + struct tee_ioctl_invoke_arg *arg, + struct tee_param *param); + int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session); + int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params, + struct tee_param *param); + int (*supp_send)(struct tee_context *ctx, u32 ret, u32 num_params, + struct tee_param *param); +}; + +/** + * struct tee_desc - Describes the TEE driver to the subsystem + * @name: name of driver + * @ops: driver operations vtable + * @owner: module providing the driver + * @flags: Extra properties of driver, defined by TEE_DESC_* below + */ +#define TEE_DESC_PRIVILEGED 0x1 +struct tee_desc { + const char *name; + const struct tee_driver_ops *ops; + struct module *owner; + u32 flags; +}; + + +/** + * tee_device_alloc() - Allocate a new struct tee_device instance + * @teedesc: Descriptor for this driver + * @dev: Parent device for this device + * @pool: Shared memory pool, NULL if not used + * @driver_data: Private driver data for this device + * + * Allocates a new struct tee_device instance. The device is + * removed by tee_device_unregister(). + * + * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure + */ +struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, + struct device *dev, struct tee_shm_pool *pool, + void *driver_data); + +/** + * tee_device_register() - Registers a TEE device + * @teedev: Device to register + * + * tee_device_unregister() need to be called to remove the @teedev if + * this function fails. + * + * @returns < 0 on failure + */ +int tee_device_register(struct tee_device *teedev); + +/** + * tee_device_unregister() - Removes a TEE device + * @teedev: Device to unregister + * + * This function should be called to remove the @teedev even if + * tee_device_register() hasn't been called yet. Does nothing if + * @teedev is NULL. + */ +void tee_device_unregister(struct tee_device *teedev); + +/** + * struct tee_shm_pool_mem_info - holds information needed to create a shared memory pool + * @vaddr: Virtual address of start of pool + * @paddr: Physical address of start of pool + * @size: Size in bytes of the pool + */ +struct tee_shm_pool_mem_info { + unsigned long vaddr; + unsigned long paddr; + size_t size; +}; + +/** + * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved memory range + * @dev: Device allocating the pool + * @priv_info: Information for driver private shared memory pool + * @dmabuf_info: Information for dma-buf shared memory pool + * + * Start and end of pools will must be page aligned. + * + * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied + * in @dmabuf, others will use the range provided by @priv. + * + * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure. + */ +struct tee_shm_pool *tee_shm_pool_alloc_res_mem(struct device *dev, + struct tee_shm_pool_mem_info *priv_info, + struct tee_shm_pool_mem_info *dmabuf_info); + +/** + * tee_shm_pool_free() - Free a shared memory pool + * @pool: The shared memory pool to free + * + * The must be no remaining shared memory allocated from this pool when + * this function is called. + */ +void tee_shm_pool_free(struct tee_shm_pool *pool); + +/** + * tee_get_drvdata() - Return driver_data pointer + * @returns the driver_data pointer supplied to tee_register(). + */ +void *tee_get_drvdata(struct tee_device *teedev); + +/** + * tee_shm_alloc() - Allocate shared memory + * @teedev: Driver that allocates the shared memory + * @size: Requested size of shared memory + * @flags: Flags setting properties for the requested shared memory. + * + * Memory allocated as global shared memory is automatically freed when the + * TEE file pointer is closed. The @flags field uses the bits defined by + * TEE_SHM_* above. TEE_SHM_MAPPED must currently always be set. If + * TEE_SHM_DMA_BUF global shared memory will be allocated and associated + * with a dma-buf handle, else driver private memory. + * + * @returns a pointer to 'struct tee_shm' + */ +struct tee_shm *tee_shm_alloc(struct tee_device *teedev, size_t size, + u32 flags); + +/** + * tee_shm_free() - Free shared memory + * @shm: Handle to shared memory to free + */ +void tee_shm_free(struct tee_shm *shm); + +/** + * tee_shm_find_by_va() - Find a shared memory handle by a virtual address + * @teedev: The device that owns the shared memory + * @flags: Select which type of shared memory to locate, if + * TEE_SHM_DMA_BUF global shared memory else driver private + * shared memory. + * @va: Virtual address covered by the shared memory + * @returns a Handle to shared memory + */ +struct tee_shm *tee_shm_find_by_va(struct tee_device *teedev, u32 flags, + void *va); +/** + * tee_shm_find_by_pa() - Find a shared memory handle by a physical address + * @teedev: The device that owns the shared memory + * @flags: Select which type of shared memory to locate, if + * TEE_SHM_DMA_BUF global shared memory else driver private + * shared memory. + * @pa: Physical address covered by the shared memory + * @returns a Handle to shared memory + */ +struct tee_shm *tee_shm_find_by_pa(struct tee_device *teedev, u32 flags, + phys_addr_t pa); + +/** + * tee_shm_va2pa() - Get physical address of a virtual address + * @shm: Shared memory handle + * @va: Virtual address to tranlsate + * @pa: Returned physical address + * @returns 0 on success and < 0 on failure + */ +int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa); + +/** + * tee_shm_pa2va() - Get virtual address of a physical address + * @shm: Shared memory handle + * @pa: Physical address to tranlsate + * @va: Returned virtual address + * @returns 0 on success and < 0 on failure + */ +int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va); + +/** + * tee_shm_get_va() - Get virtual address of a shared memory plus an offset + * @shm: Shared memory handle + * @offs: Offset from start of this shared memory + * @returns virtual address of the shared memory + offs if offs is within + * the bounds of this shared memory, else an ERR_PTR + */ +void *tee_shm_get_va(struct tee_shm *shm, size_t offs); + +/** + * tee_shm_get_pa() - Get physical address of a shared memory plus an offset + * @shm: Shared memory handle + * @offs: Offset from start of this shared memory + * @pa: Physical address to return + * @returns 0 if offs is within the bounds of this shared memory, else an + * error code. + */ +int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa); + +/** + * tee_shm_get_from_fd() - Get a shared memory handle from a file descriptor + * @fd: A user space file descriptor + * + * This function increases the reference counter on the shared memory and + * returns a handle. + * @returns handle to shared memory + */ +struct tee_shm *tee_shm_get_from_fd(int fd); + +/** + * tee_shm_put() - Decrease reference count on a shared memory handle + * @shm: Shared memory handle + */ +void tee_shm_put(struct tee_shm *shm); + +/** + * tee_shm_get_fd() - Increase reference count and return file descriptor + * @shm: Shared memory handle + * @returns user space file descriptor to shared memory + */ +int tee_shm_get_fd(struct tee_shm *shm); + +/** + * tee_shm_put_fd() - Decrease reference count and close file descriptor + * @fd: File descriptor to close + * @returns < 0 on failure + */ +int tee_shm_put_fd(int fd); + +#endif /*__TEE_DRV_H*/ diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h new file mode 100644 index 0000000..319cc61 --- /dev/null +++ b/include/uapi/linux/tee.h @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __TEE_H +#define __TEE_H + +#include +#include + +/* + * This file describes the API provided by a TEE driver to user space. + * + * Each TEE driver defines a TEE specific protocol which is used for the + * data passed back and forth using TEE_IOC_CMD. + */ + + +/* Helpers to make the ioctl defines */ +#define TEE_IOC_MAGIC 0xa4 +#define TEE_IOC_BASE 0 + +/* Flags relating to shared memory */ +#define TEE_IOCTL_SHM_MAPPED 0x1 /* memory mapped in normal world */ +#define TEE_IOCTL_SHM_DMA_BUF 0x2 /* dma-buf handle on shared memory */ + +#define TEE_MAX_ARG_SIZE 1024 + +#define TEE_GEN_CAP_GP (1 << 0)/* Global Platform compliant TEE */ + +/* + * TEE Implementation ID + */ +#define TEE_IMPL_ID_OPTEE 1 + +/* + * OP-TEE specific capabilities + */ +#define TEE_OPTEE_CAP_TZ (1 << 0) + +/** + * struct tee_ioctl_version_data - TEE version + * @impl_id: [out] TEE implementation id + * @impl_caps: [out] Implementation specific capabilities + * @gen_caps: [out] Generic capabilities, defined by TEE_GEN_CAPS_* above + * + * Identifies the TEE implementaion, @impl_id is one of TEE_IMPL_ID_* above. + * @impl_caps is implementation specific, for example TEE_OPTEE_CAP_* + * is valid when @impl_id == TEE_IMPL_ID_OPTEE. + */ +struct tee_ioctl_version_data { + __u32 impl_id; + __u32 impl_caps; + __u32 gen_caps; +}; +/** + * TEE_IOC_VERSION - query version of TEE + * + * Takes a tee_version struct and returns with the TEE version data filled + * in. + */ +#define TEE_IOC_VERSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 0, \ + struct tee_ioctl_version_data) + +/** + * struct tee_ioctl_shm_alloc_data - Shared memory allocate argument + * @size: [in/out] Size of shared memory to allocate + * @flags: [in/out] Flags to/from allocation. + * @fd: [out] dma_buf file descriptor of the shared memory + * + * The flags field should currently be zero as input. Updated by the call + * with actual flags as defined by TEE_IOCTL_SHM_* above. + * This structure is used as argument for TEE_IOC_SHM_ALLOC below. + */ +struct tee_ioctl_shm_alloc_data { + __u64 size; + __u32 flags; + __s32 fd; +}; +/** + * TEE_IOC_SHM_ALLOC - allocate shared memory + * + * Allocates shared memory between the user space process and secure OS. + * The returned file descriptor is used to map the shared memory into user + * space. The shared memory is freed when the descriptor is closed and the + * memory is unmapped. + */ +#define TEE_IOC_SHM_ALLOC _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 1, \ + struct tee_ioctl_shm_alloc_data) + +/** + * struct tee_ioctl_buf_data - Variable sized buffer + * @buf_ptr: [in] A __user pointer to a buffer + * @buf_len: [in] Length of the buffer above + * + * Used as argument for TEE_IOC_OPEN_SESSION, TEE_IOC_INVOKE, + * TEE_IOC_SUPPL_RECV, and TEE_IOC_SUPPL_SEND below. + */ +struct tee_ioctl_buf_data { + __u64 buf_ptr; + __u64 buf_len; +}; + + +/* + * Attributes for struct tee_ioctl_param, selects field in the union + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_NONE 0 /* parameter not used */ + +/* + * These defines value parameters (struct tee_ioctl_param_value) + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT 1 +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT 2 +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT 3 /* input and output */ + +/* + * These defines shared memory reference parameters (struct + * tee_ioctl_param_memref) + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT 5 +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT 6 +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7 /* input and output */ + +/* + * Mask for the type part of the attribute, leaves room for more types + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_MASK 0xff + +/* + * Matches TEEC_LOGIN_* in GP TEE Client API + * Is only defined for GP compliant TEEs + */ +#define TEE_IOCTL_LOGIN_PUBLIC 0 +#define TEE_IOCTL_LOGIN_USER 1 +#define TEE_IOCTL_LOGIN_GROUP 2 +#define TEE_IOCTL_LOGIN_APPLICATION 4 +#define TEE_IOCTL_LOGIN_USER_APPLICATION 5 +#define TEE_IOCTL_LOGIN_GROUP_APPLICATION 6 + +/** + * struct tee_ioctl_param_memref - memory reference + * @shm_offs: Offset into the shared memory object + * @size: Size of the buffer + * @shm_fd: Shared memory file descriptor + * + * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns a file + * descriptor connected to the shared memory object. A memref can reference + * a part of a shared memory by specifying an offset (@shm_offs) and @size + * of the object. To supply the entire shared memory object set @shm_offs to 0 + * and @size to the previously returned size of the object. + */ +struct tee_ioctl_param_memref { + __u64 shm_offs; + __u64 size; + __s64 shm_fd; +}; + +/** + * struct tee_ioctl_param_value - values + * @a: first value + * @b: second value + * @c: third value + */ +struct tee_ioctl_param_value { + __u64 a; + __u64 b; + __u64 c; +}; + +/** + * struct tee_ioctl_param - parameter + * @attr: attributes + * @memref: a memory reference + * @value: a value + * + * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in + * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and + * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE + * indicates that none of the members are used. + */ +struct tee_ioctl_param { + __u64 attr; + union { + struct tee_ioctl_param_memref memref; + struct tee_ioctl_param_value value; + } u; +}; + +#define TEE_IOCTL_UUID_LEN 16 + +/** + * struct tee_ioctl_open_session_arg - Open session argument + * @uuid: [in] UUID of the Trusted Application + * @clnt_uuid: [in] UUID of client + * @clnt_login: [in] Login class of client, TEE_LOGIN_* above + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @session: [out] Session id + * @ret: [out] return value + * @ret_origin [out] origin of the return value + * @num_params [in] number of parameters following this struct + */ +struct tee_ioctl_open_session_arg { + __u8 uuid[TEE_IOCTL_UUID_LEN]; + __u8 clnt_uuid[TEE_IOCTL_UUID_LEN]; + __u32 clnt_login; + __u32 cancel_id; + __u32 session; + __u32 ret; + __u32 ret_origin; + __u32 num_params; + /* + * this struct is 8 byte aligned since the 'struct tee_ioctl_param' + * which follows requires 8 byte alignment. + * + * Commented out element used to visualize the layout dynamic part + * of the struct. This field is not available at all if + * num_params == 0. + * + * struct tee_ioctl_param params[num_params]; + */ +} __aligned(8); + +/** + * TEE_IOC_OPEN_SESSION - opens a session to a Trusted Application + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_ioctl_open_session_arg followed by any array of struct + * tee_ioctl_param + */ +#define TEE_IOC_OPEN_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 2, \ + struct tee_ioctl_buf_data) + +/** + * struct tee_ioctl_invoke_func_arg - Invokes a function in a Trusted Application + * @func: [in] Trusted Application function, specific to the TA + * @session: [in] Session id + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @ret: [out] return value + * @ret_origin [out] origin of the return value + * @num_params [in] number of parameters following this struct + */ +struct tee_ioctl_invoke_arg { + __u32 func; + __u32 session; + __u32 cancel_id; + __u32 ret; + __u32 ret_origin; + __u32 num_params; + /* + * this struct is 8 byte aligned since the 'struct tee_ioctl_param' + * which follows requires 8 byte alignment. + * + * Commented out element used to visualize the layout dynamic part + * of the struct. This field is not available at all if + * num_params == 0. + * + * struct tee_ioctl_param params[num_params]; + */ +} __aligned(8); + +/** + * TEE_IOC_INVOKE - Invokes a function in a Trusted Application + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_invoke_func_arg followed by any array of struct tee_param + */ +#define TEE_IOC_INVOKE _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 3, \ + struct tee_ioctl_buf_data) + +/** + * struct tee_ioctl_cancel_arg - Cancels an open session or invoke ioctl + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @session: [in] Session id, if the session is opened, else set to 0 + */ +struct tee_ioctl_cancel_arg { + __u32 cancel_id; + __u32 session; +}; +/** + * TEE_IOC_CANCEL - Cancels an open session or invoke + */ +#define TEE_IOC_CANCEL _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 4, \ + struct tee_ioctl_cancel_arg) + +/** + * struct tee_ioctl_close_session_arg - Closes an open session + * @session: [in] Session id + */ +struct tee_ioctl_close_session_arg { + __u32 session; +}; +/** + * TEE_IOC_CLOSE_SESSION - Closes a session + */ +#define TEE_IOC_CLOSE_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 5, \ + struct tee_ioctl_close_session_arg) + +/** + * struct tee_iocl_supp_recv_arg - Receive a request for a supplicant function + * @func: [in] supplicant function + * @num_params [in/out] number of parameters following this struct + * + * @num_params is the number of params that tee-supplicant has room to + * receive when input, @num_params is the number of actual params + * tee-supplicant receives when output. + */ +struct tee_iocl_supp_recv_arg { + __u32 func; + __u32 num_params; + /* + * this struct is 8 byte aligned since the 'struct tee_ioctl_param' + * which follows requires 8 byte alignment. + * + * Commented out element used to visualize the layout dynamic part + * of the struct. This field is not available at all if + * num_params == 0. + * + * struct tee_ioctl_param params[num_params]; + */ +} __aligned(8); +/** + * TEE_IOC_SUPPL_RECV - Receive a request for a supplicant function + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_iocl_supp_recv_arg followed by any array of struct tee_param + */ +#define TEE_IOC_SUPPL_RECV _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 6, \ + struct tee_ioctl_buf_data) + + +/** + * struct tee_iocl_supp_send_arg - Send a response to a received request + * @ret: [out] return value + * @num_params [in] number of parameters following this struct + */ +struct tee_iocl_supp_send_arg { + __u32 ret; + __u32 num_params; + /* + * this struct is 8 byte aligned since the 'struct tee_ioctl_param' + * which follows requires 8 byte alignment. + * + * Commented out element used to visualize the layout dynamic part + * of the struct. This field is not available at all if + * num_params == 0. + * + * struct tee_ioctl_param params[num_params]; + */ +} __aligned(8); +/** + * TEE_IOC_SUPPL_SEND - Receive a request for a supplicant function + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_iocl_supp_send_arg followed by any array of struct tee_param + */ +#define TEE_IOC_SUPPL_SEND _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 7, \ + struct tee_ioctl_buf_data) + + +/* + * Five syscalls are used when communicating with the TEE driver. + * open(): opens the device associated with the driver + * ioctl(): as described above operating on the file descriptor from open() + * close(): two cases + * - closes the device file descriptor + * - closes a file descriptor connected to allocated shared memory + * mmap(): maps shared memory into user space using information from struct + * tee_ioctl_shm_alloc_data + * munmap(): unmaps previously shared memory + */ + +#endif /*__TEE_H*/ -- 1.9.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jens Wiklander Subject: [PATCH v7 2/4] tee: generic TEE subsystem Date: Mon, 1 Feb 2016 10:15:38 +0100 Message-ID: <1454318140-7962-3-git-send-email-jens.wiklander@linaro.org> References: <1454318140-7962-1-git-send-email-jens.wiklander@linaro.org> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: In-Reply-To: <1454318140-7962-1-git-send-email-jens.wiklander@linaro.org> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, Arnd Bergmann , Greg Kroah-Hartman Cc: valentin.manea@huawei.com, Mark Rutland , javier@javigon.com, emmanuel.michel@st.com, Will Deacon , Michal Simek , jean-michel.delorme@st.com, Jason Gunthorpe , Rob Herring , Jens Wiklander List-Id: devicetree@vger.kernel.org SW5pdGlhbCBwYXRjaCBmb3IgZ2VuZXJpYyBURUUgc3Vic3lzdGVtLgpUaGlzIHN1YnN5c3RlbSBw cm92aWRlczoKKiBSZWdpc3RyYXRpb24vdW4tcmVnaXN0cmF0aW9uIG9mIFRFRSBkcml2ZXJzLgoq IFNoYXJlZCBtZW1vcnkgYmV0d2VlbiBub3JtYWwgd29ybGQgYW5kIHNlY3VyZSB3b3JsZC4KKiBJ b2N0bCBpbnRlcmZhY2UgZm9yIGludGVyYWN0aW9uIHdpdGggdXNlciBzcGFjZS4KKiBTeXNmcyBp bXBsZW1lbnRhdGlvbl9pZCBvZiBURUUgZHJpdmVyCgpBIFRFRSAoVHJ1c3RlZCBFeGVjdXRpb24g RW52aXJvbm1lbnQpIGRyaXZlciBpcyBhIGRyaXZlciB0aGF0IGludGVyZmFjZXMKd2l0aCBhIHRy dXN0ZWQgT1MgcnVubmluZyBpbiBzb21lIHNlY3VyZSBlbnZpcm9ubWVudCwgZm9yIGV4YW1wbGUs ClRydXN0Wm9uZSBvbiBBUk0gY3B1cywgb3IgYSBzZXBhcmF0ZSBzZWN1cmUgY28tcHJvY2Vzc29y IGV0Yy4KClRoZSBURUUgc3Vic3lzdGVtIGNhbiBzZXJ2ZSBhIFRFRSBkcml2ZXIgZm9yIGEgR2xv YmFsIFBsYXRmb3JtIGNvbXBsaWFudApURUUsIGJ1dCBpdCdzIG5vdCBsaW1pdGVkIHRvIG9ubHkg R2xvYmFsIFBsYXRmb3JtIFRFRXMuCgpUaGlzIHBhdGNoIGJ1aWxkcyBvbiBvdGhlciBzaW1pbGFy IGltcGxlbWVudGF0aW9ucyB0cnlpbmcgdG8gc29sdmUKdGhlIHNhbWUgcHJvYmxlbToKKiAib3B0 ZWVfbGludXhkcml2ZXIiIGJ5IGFtb25nIG90aGVycwogIEplYW4tbWljaGVsIERFTE9STUU8amVh bi1taWNoZWwuZGVsb3JtZUBzdC5jb20+IGFuZAogIEVtbWFudWVsIE1JQ0hFTCA8ZW1tYW51ZWwu bWljaGVsQHN0LmNvbT4KKiAiR2VuZXJpYyBUcnVzdFpvbmUgRHJpdmVyIiBieSBKYXZpZXIgR29u esOhbGV6IDxqYXZpZXJAamF2aWdvbi5jb20+CgpTaWduZWQtb2ZmLWJ5OiBKZW5zIFdpa2xhbmRl ciA8amVucy53aWtsYW5kZXJAbGluYXJvLm9yZz4KLS0tCiBEb2N1bWVudGF0aW9uL2lvY3RsL2lv Y3RsLW51bWJlci50eHQgfCAgIDEgKwogTUFJTlRBSU5FUlMgICAgICAgICAgICAgICAgICAgICAg ICAgIHwgICA2ICsKIGRyaXZlcnMvS2NvbmZpZyAgICAgICAgICAgICAgICAgICAgICB8ICAgMiAr CiBkcml2ZXJzL01ha2VmaWxlICAgICAgICAgICAgICAgICAgICAgfCAgIDEgKwogZHJpdmVycy90 ZWUvS2NvbmZpZyAgICAgICAgICAgICAgICAgIHwgICA4ICsKIGRyaXZlcnMvdGVlL01ha2VmaWxl ICAgICAgICAgICAgICAgICB8ICAgMyArCiBkcml2ZXJzL3RlZS90ZWUuYyAgICAgICAgICAgICAg ICAgICAgfCA4NzMgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIGRyaXZlcnMv dGVlL3RlZV9wcml2YXRlLmggICAgICAgICAgICB8ICA4MCArKysrCiBkcml2ZXJzL3RlZS90ZWVf c2htLmMgICAgICAgICAgICAgICAgfCAzMjQgKysrKysrKysrKysrKwogZHJpdmVycy90ZWUvdGVl X3NobV9wb29sLmMgICAgICAgICAgIHwgMTMzICsrKysrKwogaW5jbHVkZS9saW51eC90ZWVfZHJ2 LmggICAgICAgICAgICAgIHwgMjk5ICsrKysrKysrKysrKwogaW5jbHVkZS91YXBpL2xpbnV4L3Rl ZS5oICAgICAgICAgICAgIHwgMzgzICsrKysrKysrKysrKysrKwogMTIgZmlsZXMgY2hhbmdlZCwg MjExMyBpbnNlcnRpb25zKCspCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy90ZWUvS2NvbmZp ZwogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdGVlL01ha2VmaWxlCiBjcmVhdGUgbW9kZSAx MDA2NDQgZHJpdmVycy90ZWUvdGVlLmMKIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3RlZS90 ZWVfcHJpdmF0ZS5oCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy90ZWUvdGVlX3NobS5jCiBj cmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy90ZWUvdGVlX3NobV9wb29sLmMKIGNyZWF0ZSBtb2Rl IDEwMDY0NCBpbmNsdWRlL2xpbnV4L3RlZV9kcnYuaAogY3JlYXRlIG1vZGUgMTAwNjQ0IGluY2x1 ZGUvdWFwaS9saW51eC90ZWUuaAoKZGlmZiAtLWdpdCBhL0RvY3VtZW50YXRpb24vaW9jdGwvaW9j dGwtbnVtYmVyLnR4dCBiL0RvY3VtZW50YXRpb24vaW9jdGwvaW9jdGwtbnVtYmVyLnR4dAppbmRl eCA5MTI2MWEzLi5iNWNlN2I2IDEwMDY0NAotLS0gYS9Eb2N1bWVudGF0aW9uL2lvY3RsL2lvY3Rs LW51bWJlci50eHQKKysrIGIvRG9jdW1lbnRhdGlvbi9pb2N0bC9pb2N0bC1udW1iZXIudHh0CkBA IC0zMDcsNiArMzA3LDcgQEAgQ29kZSAgU2VxIyhoZXgpCUluY2x1ZGUgRmlsZQkJQ29tbWVudHMK IDB4QTMJODAtOEYJUG9ydCBBQ0wJCWluIGRldmVsb3BtZW50OgogCQkJCQk8bWFpbHRvOnRsZXdp c0BtaW5kc3ByaW5nLmNvbT4KIDB4QTMJOTAtOUYJbGludXgvZHRsay5oCisweEE0CTAwLTFGCXVh cGkvbGludXgvdGVlLmgJR2VuZXJpYyBURUUgc3Vic3lzdGVtCiAweEFBCTAwLTNGCWxpbnV4L3Vh cGkvbGludXgvdXNlcmZhdWx0ZmQuaAogMHhBQgkwMC0xRglsaW51eC9uYmQuaAogMHhBQwkwMC0x RglsaW51eC9yYXcuaApkaWZmIC0tZ2l0IGEvTUFJTlRBSU5FUlMgYi9NQUlOVEFJTkVSUwppbmRl eCAzMGFjYTRhLi5lM2RmYzgxZSAxMDA2NDQKLS0tIGEvTUFJTlRBSU5FUlMKKysrIGIvTUFJTlRB SU5FUlMKQEAgLTk1NjYsNiArOTU2NiwxMiBAQCBGOglEb2N1bWVudGF0aW9uL3RyYWNlL3N0bS50 eHQKIEY6CWRyaXZlcnMvaHd0cmFjaW5nL3N0bS8KIEY6CWluY2x1ZGUvbGludXgvc3RtLmgKIEY6 CWluY2x1ZGUvdWFwaS9saW51eC9zdG0uaAorVEVFIFNVQlNZU1RFTQorTToJSmVucyBXaWtsYW5k ZXIgPGplbnMud2lrbGFuZGVyQGxpbmFyby5vcmc+CitTOglNYWludGFpbmVkCitGOglpbmNsdWRl L2xpbnV4L3RlZV9kcnYuaAorRjoJaW5jbHVkZS91YXBpL2xpbnV4L3RlZS5oCitGOglkcml2ZXJz L3RlZS8KIAogVEhVTkRFUkJPTFQgRFJJVkVSCiBNOglBbmRyZWFzIE5vZXZlciA8YW5kcmVhcy5u b2V2ZXJAZ21haWwuY29tPgpkaWZmIC0tZ2l0IGEvZHJpdmVycy9LY29uZmlnIGIvZHJpdmVycy9L Y29uZmlnCmluZGV4IGQyYWMzMzkuLjYzYmFjZWIgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvS2NvbmZp ZworKysgYi9kcml2ZXJzL0tjb25maWcKQEAgLTE5OCw0ICsxOTgsNiBAQCBzb3VyY2UgImRyaXZl cnMvaHd0cmFjaW5nL2ludGVsX3RoL0tjb25maWciCiAKIHNvdXJjZSAiZHJpdmVycy9mcGdhL0tj b25maWciCiAKK3NvdXJjZSAiZHJpdmVycy90ZWUvS2NvbmZpZyIKKwogZW5kbWVudQpkaWZmIC0t Z2l0IGEvZHJpdmVycy9NYWtlZmlsZSBiL2RyaXZlcnMvTWFrZWZpbGUKaW5kZXggOGY1ZDA3Ni4u MjMxYjQwOSAxMDA2NDQKLS0tIGEvZHJpdmVycy9NYWtlZmlsZQorKysgYi9kcml2ZXJzL01ha2Vm aWxlCkBAIC0xNzIsMyArMTcyLDQgQEAgb2JqLSQoQ09ORklHX1NUTSkJCSs9IGh3dHJhY2luZy9z dG0vCiBvYmotJChDT05GSUdfQU5EUk9JRCkJCSs9IGFuZHJvaWQvCiBvYmotJChDT05GSUdfTlZN RU0pCQkrPSBudm1lbS8KIG9iai0kKENPTkZJR19GUEdBKQkJKz0gZnBnYS8KK29iai0kKENPTkZJ R19URUUpCQkrPSB0ZWUvCmRpZmYgLS1naXQgYS9kcml2ZXJzL3RlZS9LY29uZmlnIGIvZHJpdmVy cy90ZWUvS2NvbmZpZwpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwLi42NGE4Y2Q3 Ci0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy90ZWUvS2NvbmZpZwpAQCAtMCwwICsxLDggQEAK KyMgR2VuZXJpYyBUcnVzdGVkIEV4ZWN1dGlvbiBFbnZpcm9ubWVudCBDb25maWd1cmF0aW9uCitj b25maWcgVEVFCisJYm9vbCAiVHJ1c3RlZCBFeGVjdXRpb24gRW52aXJvbm1lbnQgc3VwcG9ydCIK KwlkZWZhdWx0IG4KKwlzZWxlY3QgRE1BX1NIQVJFRF9CVUZGRVIKKwloZWxwCisJICBUaGlzIGlt cGxlbWVudHMgYSBnZW5lcmljIGludGVyZmFjZSB0b3dhcmRzIGEgVHJ1c3RlZCBFeGVjdXRpb24K KwkgIEVudmlyb25tZW50IChURUUpLgpkaWZmIC0tZ2l0IGEvZHJpdmVycy90ZWUvTWFrZWZpbGUg Yi9kcml2ZXJzL3RlZS9NYWtlZmlsZQpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAw Li42MGQyZGFiCi0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy90ZWUvTWFrZWZpbGUKQEAgLTAs MCArMSwzIEBACitvYmoteSArPSB0ZWUubworb2JqLXkgKz0gdGVlX3NobS5vCitvYmoteSArPSB0 ZWVfc2htX3Bvb2wubwpkaWZmIC0tZ2l0IGEvZHJpdmVycy90ZWUvdGVlLmMgYi9kcml2ZXJzL3Rl ZS90ZWUuYwpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwLi5iOGExYzc2Ci0tLSAv ZGV2L251bGwKKysrIGIvZHJpdmVycy90ZWUvdGVlLmMKQEAgLTAsMCArMSw4NzMgQEAKKy8qCisg KiBDb3B5cmlnaHQgKGMpIDIwMTUsIExpbmFybyBMaW1pdGVkCisgKgorICogVGhpcyBzb2Z0d2Fy ZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYwor ICogTGljZW5zZSB2ZXJzaW9uIDIsIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBG b3VuZGF0aW9uLCBhbmQKKyAqIG1heSBiZSBjb3BpZWQsIGRpc3RyaWJ1dGVkLCBhbmQgbW9kaWZp ZWQgdW5kZXIgdGhvc2UgdGVybXMuCisgKgorICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVk IGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCisgKiBidXQgV0lUSE9VVCBBTlkg V0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgorICogTUVSQ0hB TlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQor ICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KKyAqCisgKi8K KyNpbmNsdWRlIDxsaW51eC9kZXZpY2UuaD4KKyNpbmNsdWRlIDxsaW51eC9jZGV2Lmg+CisjaW5j bHVkZSA8bGludXgvZnMuaD4KKyNpbmNsdWRlIDxsaW51eC9zbGFiLmg+CisjaW5jbHVkZSA8bGlu dXgvdWFjY2Vzcy5oPgorI2luY2x1ZGUgPGxpbnV4L3RlZV9kcnYuaD4KKyNpbmNsdWRlICJ0ZWVf cHJpdmF0ZS5oIgorCisjZGVmaW5lIFRFRV9OVU1fREVWSUNFUwkzMgorCisjZGVmaW5lIFRFRV9J T0NUTF9QQVJBTV9TSVpFKHgpIChzaXplb2Yoc3RydWN0IHRlZV9wYXJhbSkgKiAoeCkpCisKKy8q CisgKiBVbnByaXZpbGVnZWQgZGV2aWNlcyBpbiB0aGUgaW4gdGhlIGxvd2VyIGhhbGYgcmFuZ2Ug YW5kIHByaXZpbGVnZWQKKyAqIGRldmljZXMgaW4gdGhlIHVwcGVyIGhhbGYgcmFuZ2UuCisgKi8K K3N0YXRpYyBERUNMQVJFX0JJVE1BUChkZXZfbWFzaywgVEVFX05VTV9ERVZJQ0VTKTsKK3N0YXRp YyBERUZJTkVfU1BJTkxPQ0soZHJpdmVyX2xvY2spOworCitzdGF0aWMgc3RydWN0IGNsYXNzICp0 ZWVfY2xhc3M7CitzdGF0aWMgZGV2X3QgdGVlX2RldnQ7CisKK3N0YXRpYyBpbnQgdGVlX29wZW4o c3RydWN0IGlub2RlICppbm9kZSwgc3RydWN0IGZpbGUgKmZpbHApCit7CisJaW50IHJjOworCXN0 cnVjdCB0ZWVfZGV2aWNlICp0ZWVkZXY7CisJc3RydWN0IHRlZV9jb250ZXh0ICpjdHg7CisKKwl0 ZWVkZXYgPSBjb250YWluZXJfb2YoaW5vZGUtPmlfY2Rldiwgc3RydWN0IHRlZV9kZXZpY2UsIGNk ZXYpOworCWlmICghdGVlX2RldmljZV9nZXQodGVlZGV2KSkKKwkJcmV0dXJuIC1FSU5WQUw7CisK KwljdHggPSBremFsbG9jKHNpemVvZigqY3R4KSwgR0ZQX0tFUk5FTCk7CisJaWYgKCFjdHgpIHsK KwkJcmMgPSAtRU5PTUVNOworCQlnb3RvIGVycjsKKwl9CisKKwljdHgtPnRlZWRldiA9IHRlZWRl djsKKwlmaWxwLT5wcml2YXRlX2RhdGEgPSBjdHg7CisJcmMgPSB0ZWVkZXYtPmRlc2MtPm9wcy0+ b3BlbihjdHgpOworCWlmIChyYykKKwkJZ290byBlcnI7CisKKwlyZXR1cm4gMDsKK2VycjoKKwlr ZnJlZShjdHgpOworCXRlZV9kZXZpY2VfcHV0KHRlZWRldik7CisJcmV0dXJuIHJjOworfQorCitz dGF0aWMgaW50IHRlZV9yZWxlYXNlKHN0cnVjdCBpbm9kZSAqaW5vZGUsIHN0cnVjdCBmaWxlICpm aWxwKQoreworCXN0cnVjdCB0ZWVfY29udGV4dCAqY3R4ID0gZmlscC0+cHJpdmF0ZV9kYXRhOwor CXN0cnVjdCB0ZWVfZGV2aWNlICp0ZWVkZXYgPSBjdHgtPnRlZWRldjsKKworCWN0eC0+dGVlZGV2 LT5kZXNjLT5vcHMtPnJlbGVhc2UoY3R4KTsKKwlrZnJlZShjdHgpOworCXRlZV9kZXZpY2VfcHV0 KHRlZWRldik7CisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgdGVlX2lvY3RsX3ZlcnNpb24o c3RydWN0IHRlZV9jb250ZXh0ICpjdHgsCisJCXN0cnVjdCB0ZWVfaW9jdGxfdmVyc2lvbl9kYXRh IF9fdXNlciAqdXZlcnMpCit7CisJc3RydWN0IHRlZV9pb2N0bF92ZXJzaW9uX2RhdGEgdmVyczsK KworCWN0eC0+dGVlZGV2LT5kZXNjLT5vcHMtPmdldF92ZXJzaW9uKGN0eC0+dGVlZGV2LCAmdmVy cyk7CisJaWYgKGNvcHlfdG9fdXNlcih1dmVycywgJnZlcnMsIHNpemVvZih2ZXJzKSkpCisJCXJl dHVybiAtRUZBVUxUOworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IHRlZV9pb2N0bF9zaG1f YWxsb2Moc3RydWN0IHRlZV9jb250ZXh0ICpjdHgsCisJCXN0cnVjdCB0ZWVfaW9jdGxfc2htX2Fs bG9jX2RhdGEgX191c2VyICp1ZGF0YSkKK3sKKwlsb25nIHJldDsKKwlzdHJ1Y3QgdGVlX2lvY3Rs X3NobV9hbGxvY19kYXRhIGRhdGE7CisJc3RydWN0IHRlZV9zaG0gKnNobTsKKworCWlmIChjb3B5 X2Zyb21fdXNlcigmZGF0YSwgdWRhdGEsIHNpemVvZihkYXRhKSkpCisJCXJldHVybiAtRUZBVUxU OworCisJLyogQ3VycmVudGx5IG5vIGlucHV0IGZsYWdzIGFyZSBzdXBwb3J0ZWQgKi8KKwlpZiAo ZGF0YS5mbGFncykKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwlkYXRhLmZkID0gLTE7CisKKwlzaG0g PSB0ZWVfc2htX2FsbG9jKGN0eC0+dGVlZGV2LCBkYXRhLnNpemUsCisJCQkgICAgVEVFX1NITV9N QVBQRUQgfCBURUVfU0hNX0RNQV9CVUYpOworCWlmIChJU19FUlIoc2htKSkKKwkJcmV0dXJuIFBU Ul9FUlIoc2htKTsKKworCWRhdGEuZmxhZ3MgPSBzaG0tPmZsYWdzOworCWRhdGEuc2l6ZSA9IHNo bS0+c2l6ZTsKKwlkYXRhLmZkID0gdGVlX3NobV9nZXRfZmQoc2htKTsKKwlpZiAoZGF0YS5mZCA8 IDApIHsKKwkJcmV0ID0gZGF0YS5mZDsKKwkJZ290byBlcnI7CisJfQorCisJaWYgKGNvcHlfdG9f dXNlcih1ZGF0YSwgJmRhdGEsIHNpemVvZihkYXRhKSkpIHsKKwkJcmV0ID0gLUVGQVVMVDsKKwkJ Z290byBlcnI7CisJfQorCS8qCisJICogV2hlbiB1c2VyIHNwYWNlIGNsb3NlcyB0aGUgZmlsZSBk ZXNjcmlwdG9yIHRoZSBzaGFyZWQgbWVtb3J5CisJICogc2hvdWxkIGJlIGZyZWVkCisJICovCisJ dGVlX3NobV9wdXQoc2htKTsKKwlyZXR1cm4gMDsKK2VycjoKKwlpZiAoZGF0YS5mZCA+PSAwKQor CQl0ZWVfc2htX3B1dF9mZChkYXRhLmZkKTsKKwl0ZWVfc2htX2ZyZWUoc2htKTsKKwlyZXR1cm4g cmV0OworfQorCitzdGF0aWMgaW50IHBhcmFtc19mcm9tX3VzZXIoc3RydWN0IHRlZV9wYXJhbSAq cGFyYW1zLCBzaXplX3QgbnVtX3BhcmFtcywKKwkJc3RydWN0IHRlZV9pb2N0bF9wYXJhbSBfX3Vz ZXIgKnVwYXJhbXMpCit7CisJc2l6ZV90IG47CisKKwlmb3IgKG4gPSAwOyBuIDwgbnVtX3BhcmFt czsgbisrKSB7CisJCXN0cnVjdCB0ZWVfc2htICpzaG07CisJCXN0cnVjdCB0ZWVfaW9jdGxfcGFy YW0gaXA7CisKKwkJaWYgKGNvcHlfZnJvbV91c2VyKCZpcCwgdXBhcmFtcyArIG4sIHNpemVvZihp cCkpKQorCQkJcmV0dXJuIC1FRkFVTFQ7CisKKwkJLyogQWxsIHVudXNlZCBhdHRyaWJ1dGUgYml0 cyBoYXMgdG8gYmUgemVybyAqLworCQlpZiAoaXAuYXR0ciAmIH5URUVfSU9DVExfUEFSQU1fQVRU Ul9UWVBFX01BU0spCisJCQlyZXR1cm4gLUVJTlZBTDsKKworCQlwYXJhbXNbbl0uYXR0ciA9IGlw LmF0dHI7CisJCXN3aXRjaCAoaXAuYXR0cikgeworCQljYXNlIFRFRV9JT0NUTF9QQVJBTV9BVFRS X1RZUEVfTk9ORToKKwkJY2FzZSBURUVfSU9DVExfUEFSQU1fQVRUUl9UWVBFX1ZBTFVFX09VVFBV VDoKKwkJCWJyZWFrOworCQljYXNlIFRFRV9JT0NUTF9QQVJBTV9BVFRSX1RZUEVfVkFMVUVfSU5Q VVQ6CisJCWNhc2UgVEVFX0lPQ1RMX1BBUkFNX0FUVFJfVFlQRV9WQUxVRV9JTk9VVDoKKwkJCXBh cmFtc1tuXS51LnZhbHVlLmEgPSBpcC51LnZhbHVlLmE7CisJCQlwYXJhbXNbbl0udS52YWx1ZS5i ID0gaXAudS52YWx1ZS5iOworCQkJcGFyYW1zW25dLnUudmFsdWUuYyA9IGlwLnUudmFsdWUuYzsK KwkJCWJyZWFrOworCQljYXNlIFRFRV9JT0NUTF9QQVJBTV9BVFRSX1RZUEVfTUVNUkVGX0lOUFVU OgorCQljYXNlIFRFRV9JT0NUTF9QQVJBTV9BVFRSX1RZUEVfTUVNUkVGX09VVFBVVDoKKwkJY2Fz ZSBURUVfSU9DVExfUEFSQU1fQVRUUl9UWVBFX01FTVJFRl9JTk9VVDoKKwkJCS8qCisJCQkgKiBJ ZiB3ZSBmYWlsIHRvIGdldCBhIHBvaW50ZXIgdG8gYSBzaGFyZWQgbWVtb3J5CisJCQkgKiBvYmpl Y3QgKGFuZCBpbmNyZWFzZSB0aGUgcmVmIGNvdW50KSBmcm9tIGEgZmlsZQorCQkJICogZGVzY3Jp cHRvciB3ZSByZXR1cm4gYW4gZXJyb3IuIEFsbCBwb2ludGVycyB0aGF0CisJCQkgKiBoYXMgYmVl biBhZGRlZCBpbiBwYXJhbXMgaGF2ZSBhbiBpbmNyZWFzZWQgcmVmCisJCQkgKiBjb3VudC4gSXQn cyB0aGUgY2FsbGVycyByZXNwb25pYmlsaXR5IHRvIGRvCisJCQkgKiB0ZWVfc2htX3B1dCgpIG9u IGFsbCByZXNvbHZlZCBwb2ludGVycy4KKwkJCSAqLworCQkJc2htID0gdGVlX3NobV9nZXRfZnJv bV9mZChpcC51Lm1lbXJlZi5zaG1fZmQpOworCQkJaWYgKElTX0VSUihzaG0pKQorCQkJCXJldHVy biBQVFJfRVJSKHNobSk7CisKKwkJCXBhcmFtc1tuXS51Lm1lbXJlZi5zaG1fb2ZmcyA9IGlwLnUu bWVtcmVmLnNobV9vZmZzOworCQkJcGFyYW1zW25dLnUubWVtcmVmLnNpemUgPSBpcC51Lm1lbXJl Zi5zaXplOworCQkJcGFyYW1zW25dLnUubWVtcmVmLnNobSA9IHNobTsKKwkJCWJyZWFrOworCQlk ZWZhdWx0OgorCQkJLyogVW5rbm93biBhdHRyaWJ1dGUgKi8KKwkJCXJldHVybiAtRUlOVkFMOwor CQl9CisJfQorCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IHBhcmFtc190b191c2VyKHN0cnVj dCB0ZWVfaW9jdGxfcGFyYW0gX191c2VyICp1cGFyYW1zLAorCQlzaXplX3QgbnVtX3BhcmFtcywg c3RydWN0IHRlZV9wYXJhbSAqcGFyYW1zKQoreworCXNpemVfdCBuOworCisJZm9yIChuID0gMDsg biA8IG51bV9wYXJhbXM7IG4rKykgeworCQlzdHJ1Y3QgdGVlX2lvY3RsX3BhcmFtIF9fdXNlciAq dXAgPSB1cGFyYW1zICsgbjsKKwkJc3RydWN0IHRlZV9wYXJhbSAqcCA9IHBhcmFtcyArIG47CisK KwkJc3dpdGNoIChwLT5hdHRyKSB7CisJCWNhc2UgVEVFX0lPQ1RMX1BBUkFNX0FUVFJfVFlQRV9W QUxVRV9PVVRQVVQ6CisJCWNhc2UgVEVFX0lPQ1RMX1BBUkFNX0FUVFJfVFlQRV9WQUxVRV9JTk9V VDoKKwkJCWlmIChwdXRfdXNlcihwLT51LnZhbHVlLmEsICZ1cC0+dS52YWx1ZS5hKSB8fAorCQkJ ICAgIHB1dF91c2VyKHAtPnUudmFsdWUuYiwgJnVwLT51LnZhbHVlLmIpIHx8CisJCQkgICAgcHV0 X3VzZXIocC0+dS52YWx1ZS5jLCAmdXAtPnUudmFsdWUuYykpCisJCQkJcmV0dXJuIC1FRkFVTFQ7 CisJCQlicmVhazsKKwkJY2FzZSBURUVfSU9DVExfUEFSQU1fQVRUUl9UWVBFX01FTVJFRl9PVVRQ VVQ6CisJCWNhc2UgVEVFX0lPQ1RMX1BBUkFNX0FUVFJfVFlQRV9NRU1SRUZfSU5PVVQ6CisJCQlp ZiAocHV0X3VzZXIoKHU2NClwLT51Lm1lbXJlZi5zaXplLCAmdXAtPnUubWVtcmVmLnNpemUpKQor CQkJCXJldHVybiAtRUZBVUxUOworCQlkZWZhdWx0OgorCQkJYnJlYWs7CisJCX0KKwl9CisJcmV0 dXJuIDA7Cit9CisKK3N0YXRpYyBib29sIHBhcmFtX2lzX21lbXJlZihzdHJ1Y3QgdGVlX3BhcmFt ICpwYXJhbSkKK3sKKwlzd2l0Y2ggKHBhcmFtLT5hdHRyICYgVEVFX0lPQ1RMX1BBUkFNX0FUVFJf VFlQRV9NQVNLKSB7CisJY2FzZSBURUVfSU9DVExfUEFSQU1fQVRUUl9UWVBFX01FTVJFRl9JTlBV VDoKKwljYXNlIFRFRV9JT0NUTF9QQVJBTV9BVFRSX1RZUEVfTUVNUkVGX09VVFBVVDoKKwljYXNl IFRFRV9JT0NUTF9QQVJBTV9BVFRSX1RZUEVfTUVNUkVGX0lOT1VUOgorCQlyZXR1cm4gdHJ1ZTsK KwlkZWZhdWx0OgorCQlyZXR1cm4gZmFsc2U7CisJfQorfQorCitzdGF0aWMgaW50IHRlZV9pb2N0 bF9vcGVuX3Nlc3Npb24oc3RydWN0IHRlZV9jb250ZXh0ICpjdHgsCisJCXN0cnVjdCB0ZWVfaW9j dGxfYnVmX2RhdGEgX191c2VyICp1YnVmKQoreworCWludCByYzsKKwlzaXplX3QgbjsKKwlzdHJ1 Y3QgdGVlX2lvY3RsX2J1Zl9kYXRhIGJ1ZjsKKwlzdHJ1Y3QgdGVlX2lvY3RsX29wZW5fc2Vzc2lv bl9hcmcgX191c2VyICp1YXJnOworCXN0cnVjdCB0ZWVfaW9jdGxfb3Blbl9zZXNzaW9uX2FyZyBh cmc7CisJc3RydWN0IHRlZV9pb2N0bF9wYXJhbSBfX3VzZXIgKnVwYXJhbXMgPSBOVUxMOworCXN0 cnVjdCB0ZWVfcGFyYW0gKnBhcmFtcyA9IE5VTEw7CisJYm9vbCBoYXZlX3Nlc3Npb24gPSBmYWxz ZTsKKworCWlmICghY3R4LT50ZWVkZXYtPmRlc2MtPm9wcy0+b3Blbl9zZXNzaW9uKQorCQlyZXR1 cm4gLUVJTlZBTDsKKworCWlmIChjb3B5X2Zyb21fdXNlcigmYnVmLCB1YnVmLCBzaXplb2YoYnVm KSkpCisJCXJldHVybiAtRUZBVUxUOworCisJaWYgKGJ1Zi5idWZfbGVuID4gVEVFX01BWF9BUkdf U0laRSB8fAorCSAgICBidWYuYnVmX2xlbiA8IHNpemVvZihzdHJ1Y3QgdGVlX2lvY3RsX29wZW5f c2Vzc2lvbl9hcmcpKQorCQlyZXR1cm4gLUVJTlZBTDsKKworCXVhcmcgPSAoc3RydWN0IHRlZV9p b2N0bF9vcGVuX3Nlc3Npb25fYXJnIF9fdXNlciAqKSh1bnNpZ25lZCBsb25nKQorCQlidWYuYnVm X3B0cjsKKwlyYyA9IGNvcHlfZnJvbV91c2VyKCZhcmcsIHVhcmcsIHNpemVvZihhcmcpKTsKKwlp ZiAocmMpCisJCXJldHVybiByYzsKKworCWlmIChzaXplb2YoYXJnKSArIFRFRV9JT0NUTF9QQVJB TV9TSVpFKGFyZy5udW1fcGFyYW1zKSAhPSBidWYuYnVmX2xlbikKKwkJcmV0dXJuIC1FSU5WQUw7 CisKKwlpZiAoYXJnLm51bV9wYXJhbXMpIHsKKwkJcGFyYW1zID0ga2NhbGxvYyhhcmcubnVtX3Bh cmFtcywgc2l6ZW9mKHN0cnVjdCB0ZWVfcGFyYW0pLAorCQkJCUdGUF9LRVJORUwpOworCQlpZiAo IXBhcmFtcykKKwkJCXJldHVybiAtRU5PTUVNOworCQl1cGFyYW1zID0gKHN0cnVjdCB0ZWVfaW9j dGxfcGFyYW0gX191c2VyICopKHVhcmcgKyAxKTsKKwkJcmMgPSBwYXJhbXNfZnJvbV91c2VyKHBh cmFtcywgYXJnLm51bV9wYXJhbXMsIHVwYXJhbXMpOworCQlpZiAocmMpCisJCQlnb3RvIG91dDsK Kwl9CisKKwlyYyA9IGN0eC0+dGVlZGV2LT5kZXNjLT5vcHMtPm9wZW5fc2Vzc2lvbihjdHgsICZh cmcsIHBhcmFtcyk7CisJaWYgKHJjKQorCQlnb3RvIG91dDsKKwloYXZlX3Nlc3Npb24gPSB0cnVl OworCisJaWYgKHB1dF91c2VyKGFyZy5zZXNzaW9uLCAmdWFyZy0+c2Vzc2lvbikgfHwKKwkgICAg cHV0X3VzZXIoYXJnLnJldCwgJnVhcmctPnJldCkgfHwKKwkgICAgcHV0X3VzZXIoYXJnLnJldF9v cmlnaW4sICZ1YXJnLT5yZXRfb3JpZ2luKSkgeworCQlyYyA9IC1FRkFVTFQ7CisJCWdvdG8gb3V0 OworCX0KKwlyYyA9IHBhcmFtc190b191c2VyKHVwYXJhbXMsIGFyZy5udW1fcGFyYW1zLCBwYXJh bXMpOworb3V0OgorCS8qCisJICogSWYgd2UndmUgc3VjY2VlZGVkIHRvIG9wZW4gdGhlIHNlc3Np b24gYnV0IGZhaWxlZCB0byBjb21tdW5pY2F0ZQorCSAqIGl0IGJhY2sgdG8gdXNlciBzcGFjZSwg Y2xvc2UgdGhlIHNlc3Npb24gYWdhaW4gdG8gYXZvaWQgbGVha2FnZS4KKwkgKi8KKwlpZiAocmMg JiYgaGF2ZV9zZXNzaW9uICYmIGN0eC0+dGVlZGV2LT5kZXNjLT5vcHMtPmNsb3NlX3Nlc3Npb24p CisJCWN0eC0+dGVlZGV2LT5kZXNjLT5vcHMtPmNsb3NlX3Nlc3Npb24oY3R4LCBhcmcuc2Vzc2lv bik7CisKKwlpZiAocGFyYW1zKSB7CisJCS8qIERlY3JlYXNlIHJlZiBjb3VudCBmb3IgYWxsIHZh bGlkIHNoYXJlZCBtZW1vcnkgcG9pbnRlcnMgKi8KKwkJZm9yIChuID0gMDsgbiA8IGFyZy5udW1f cGFyYW1zOyBuKyspCisJCQlpZiAocGFyYW1faXNfbWVtcmVmKHBhcmFtcyArIG4pICYmCisJCQkg ICAgcGFyYW1zW25dLnUubWVtcmVmLnNobSkKKwkJCQl0ZWVfc2htX3B1dChwYXJhbXNbbl0udS5t ZW1yZWYuc2htKTsKKwkJa2ZyZWUocGFyYW1zKTsKKwl9CisKKwlyZXR1cm4gcmM7Cit9CisKK3N0 YXRpYyBpbnQgdGVlX2lvY3RsX2ludm9rZShzdHJ1Y3QgdGVlX2NvbnRleHQgKmN0eCwKKwkJc3Ry dWN0IHRlZV9pb2N0bF9idWZfZGF0YSBfX3VzZXIgKnVidWYpCit7CisJaW50IHJjOworCXNpemVf dCBuOworCXN0cnVjdCB0ZWVfaW9jdGxfYnVmX2RhdGEgYnVmOworCXN0cnVjdCB0ZWVfaW9jdGxf aW52b2tlX2FyZyBfX3VzZXIgKnVhcmc7CisJc3RydWN0IHRlZV9pb2N0bF9pbnZva2VfYXJnIGFy ZzsKKwlzdHJ1Y3QgdGVlX2lvY3RsX3BhcmFtIF9fdXNlciAqdXBhcmFtcyA9IE5VTEw7CisJc3Ry dWN0IHRlZV9wYXJhbSAqcGFyYW1zID0gTlVMTDsKKworCWlmICghY3R4LT50ZWVkZXYtPmRlc2Mt Pm9wcy0+aW52b2tlX2Z1bmMpCisJCXJldHVybiAtRUlOVkFMOworCisJcmMgPSBjb3B5X2Zyb21f dXNlcigmYnVmLCB1YnVmLCBzaXplb2YoYnVmKSk7CisJaWYgKHJjKQorCQlyZXR1cm4gcmM7CisK KwlpZiAoYnVmLmJ1Zl9sZW4gPiBURUVfTUFYX0FSR19TSVpFIHx8CisJICAgIGJ1Zi5idWZfbGVu IDwgc2l6ZW9mKHN0cnVjdCB0ZWVfaW9jdGxfaW52b2tlX2FyZykpCisJCXJldHVybiAtRUlOVkFM OworCisJdWFyZyA9IChzdHJ1Y3QgdGVlX2lvY3RsX2ludm9rZV9hcmcgX191c2VyICopKHVuc2ln bmVkIGxvbmcpYnVmLmJ1Zl9wdHI7CisJaWYgKGNvcHlfZnJvbV91c2VyKCZhcmcsIHVhcmcsIHNp emVvZihhcmcpKSkKKwkJcmV0dXJuIC1FRkFVTFQ7CisKKwlpZiAoc2l6ZW9mKGFyZykgKyBURUVf SU9DVExfUEFSQU1fU0laRShhcmcubnVtX3BhcmFtcykgIT0gYnVmLmJ1Zl9sZW4pCisJCXJldHVy biAtRUlOVkFMOworCisJaWYgKGFyZy5udW1fcGFyYW1zKSB7CisJCXBhcmFtcyA9IGtjYWxsb2Mo YXJnLm51bV9wYXJhbXMsIHNpemVvZihzdHJ1Y3QgdGVlX3BhcmFtKSwKKwkJCQlHRlBfS0VSTkVM KTsKKwkJaWYgKCFwYXJhbXMpCisJCQlyZXR1cm4gLUVOT01FTTsKKwkJdXBhcmFtcyA9IChzdHJ1 Y3QgdGVlX2lvY3RsX3BhcmFtIF9fdXNlciAqKSh1YXJnICsgMSk7CisJCXJjID0gcGFyYW1zX2Zy b21fdXNlcihwYXJhbXMsIGFyZy5udW1fcGFyYW1zLCB1cGFyYW1zKTsKKwkJaWYgKHJjKQorCQkJ Z290byBvdXQ7CisJfQorCisJcmMgPSBjdHgtPnRlZWRldi0+ZGVzYy0+b3BzLT5pbnZva2VfZnVu YyhjdHgsICZhcmcsIHBhcmFtcyk7CisJaWYgKHJjKQorCQlnb3RvIG91dDsKKworCWlmIChwdXRf dXNlcihhcmcucmV0LCAmdWFyZy0+cmV0KSB8fAorCSAgICBwdXRfdXNlcihhcmcucmV0X29yaWdp biwgJnVhcmctPnJldF9vcmlnaW4pKSB7CisJCXJjID0gLUVGQVVMVDsKKwkJZ290byBvdXQ7CisJ fQorCXJjID0gcGFyYW1zX3RvX3VzZXIodXBhcmFtcywgYXJnLm51bV9wYXJhbXMsIHBhcmFtcyk7 CitvdXQ6CisJaWYgKHBhcmFtcykgeworCQkvKiBEZWNyZWFzZSByZWYgY291bnQgZm9yIGFsbCB2 YWxpZCBzaGFyZWQgbWVtb3J5IHBvaW50ZXJzICovCisJCWZvciAobiA9IDA7IG4gPCBhcmcubnVt X3BhcmFtczsgbisrKQorCQkJaWYgKHBhcmFtX2lzX21lbXJlZihwYXJhbXMgKyBuKSAmJgorCQkJ ICAgIHBhcmFtc1tuXS51Lm1lbXJlZi5zaG0pCisJCQkJdGVlX3NobV9wdXQocGFyYW1zW25dLnUu bWVtcmVmLnNobSk7CisJCWtmcmVlKHBhcmFtcyk7CisJfQorCXJldHVybiByYzsKK30KKworCitz dGF0aWMgaW50IHRlZV9pb2N0bF9jYW5jZWwoc3RydWN0IHRlZV9jb250ZXh0ICpjdHgsCisJCXN0 cnVjdCB0ZWVfaW9jdGxfY2FuY2VsX2FyZyBfX3VzZXIgKnVhcmcpCit7CisJc3RydWN0IHRlZV9p b2N0bF9jYW5jZWxfYXJnIGFyZzsKKworCWlmICghY3R4LT50ZWVkZXYtPmRlc2MtPm9wcy0+Y2Fu Y2VsX3JlcSkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwlpZiAoY29weV9mcm9tX3VzZXIoJmFyZywg dWFyZywgc2l6ZW9mKGFyZykpKQorCQlyZXR1cm4gLUVGQVVMVDsKKworCXJldHVybiBjdHgtPnRl ZWRldi0+ZGVzYy0+b3BzLT5jYW5jZWxfcmVxKGN0eCwgYXJnLmNhbmNlbF9pZCwKKwkJCQkJCSAg YXJnLnNlc3Npb24pOworfQorCitzdGF0aWMgaW50IHRlZV9pb2N0bF9jbG9zZV9zZXNzaW9uKHN0 cnVjdCB0ZWVfY29udGV4dCAqY3R4LAorCQlzdHJ1Y3QgdGVlX2lvY3RsX2Nsb3NlX3Nlc3Npb25f YXJnIF9fdXNlciAqdWFyZykKK3sKKwlzdHJ1Y3QgdGVlX2lvY3RsX2Nsb3NlX3Nlc3Npb25fYXJn IGFyZzsKKworCWlmICghY3R4LT50ZWVkZXYtPmRlc2MtPm9wcy0+Y2xvc2Vfc2Vzc2lvbikKKwkJ cmV0dXJuIC1FSU5WQUw7CisKKwlpZiAoY29weV9mcm9tX3VzZXIoJmFyZywgdWFyZywgc2l6ZW9m KGFyZykpKQorCQlyZXR1cm4gLUVGQVVMVDsKKworCXJldHVybiBjdHgtPnRlZWRldi0+ZGVzYy0+ b3BzLT5jbG9zZV9zZXNzaW9uKGN0eCwgYXJnLnNlc3Npb24pOworfQorCitzdGF0aWMgaW50IHBh cmFtc190b19zdXBwKHN0cnVjdCB0ZWVfaW9jdGxfcGFyYW0gX191c2VyICp1cGFyYW1zLAorCQlz aXplX3QgbnVtX3BhcmFtcywgc3RydWN0IHRlZV9wYXJhbSAqcGFyYW1zKQoreworCWludCByYyA9 IDA7CisJc2l6ZV90IG47CisJaW50ICpmZHMgPSBrbWFsbG9jX2FycmF5KG51bV9wYXJhbXMsIHNp emVvZihpbnQpLCBHRlBfS0VSTkVMKTsKKworCWlmICghZmRzKQorCQlyZXR1cm4gLUVOT01FTTsK Kwlmb3IgKG4gPSAwOyBuIDwgbnVtX3BhcmFtczsgbisrKQorCQlmZHNbbl0gPSAtMTsKKworCWZv ciAobiA9IDA7IG4gPCBudW1fcGFyYW1zOyBuKyspIHsKKwkJc3RydWN0IHRlZV9pb2N0bF9wYXJh bSBpcDsKKwkJc3RydWN0IHRlZV9wYXJhbSAqcCA9IHBhcmFtcyArIG47CisKKwkJaXAuYXR0ciA9 IHAtPmF0dHIgJiBURUVfSU9DVExfUEFSQU1fQVRUUl9UWVBFX01BU0s7CisJCXN3aXRjaCAocC0+ YXR0cikgeworCQljYXNlIFRFRV9JT0NUTF9QQVJBTV9BVFRSX1RZUEVfVkFMVUVfSU5QVVQ6CisJ CWNhc2UgVEVFX0lPQ1RMX1BBUkFNX0FUVFJfVFlQRV9WQUxVRV9JTk9VVDoKKwkJCWlwLnUudmFs dWUuYSA9IHAtPnUudmFsdWUuYTsKKwkJCWlwLnUudmFsdWUuYiA9IHAtPnUudmFsdWUuYjsKKwkJ CWlwLnUudmFsdWUuYyA9IHAtPnUudmFsdWUuYzsKKwkJCWJyZWFrOworCQljYXNlIFRFRV9JT0NU TF9QQVJBTV9BVFRSX1RZUEVfTUVNUkVGX0lOUFVUOgorCQljYXNlIFRFRV9JT0NUTF9QQVJBTV9B VFRSX1RZUEVfTUVNUkVGX09VVFBVVDoKKwkJY2FzZSBURUVfSU9DVExfUEFSQU1fQVRUUl9UWVBF X01FTVJFRl9JTk9VVDoKKwkJCWlwLnUubWVtcmVmLnNpemUgPSBwLT51Lm1lbXJlZi5zaXplOwor CQkJaWYgKCFwLT51Lm1lbXJlZi5zaG0pIHsKKwkJCQlpcC51Lm1lbXJlZi5zaG1fb2ZmcyA9IDA7 CisJCQkJaXAudS5tZW1yZWYuc2htX2ZkID0gLTE7CisJCQkJYnJlYWs7CisJCQl9CisJCQlpcC51 Lm1lbXJlZi5zaG1fb2ZmcyA9IHAtPnUubWVtcmVmLnNobV9vZmZzOworCQkJLyoKKwkJCSAqIFRo aXMgdGVlX3NobV9nZXRfZmQoKSBpcyBzdXBwb3NlZCB0byBiZSBtYXRjaGVkCisJCQkgKiBieSBh IGNsb3NlKDIpIGZyb20gdGVlLXN1cHBsaWNhbnQuCisJCQkgKi8KKwkJCWZkc1tuXSA9IHRlZV9z aG1fZ2V0X2ZkKHAtPnUubWVtcmVmLnNobSk7CisJCQlpZiAoZmRzW25dIDwgMCkgeworCQkJCXJj ID0gZmRzW25dOworCQkJCWdvdG8gb3V0OworCQkJfQorCQkJaXAudS5tZW1yZWYuc2htX2ZkID0g ZmRzW25dOworCQkJYnJlYWs7CisJCWRlZmF1bHQ6CisJCQltZW1zZXQoJmlwLnUsIDAsIHNpemVv ZihpcC51KSk7CisJCQlicmVhazsKKwkJfQorCisJCWlmIChjb3B5X3RvX3VzZXIodXBhcmFtcyAr IG4sICZpcCwgc2l6ZW9mKGlwKSkpIHsKKwkJCXJjID0gLUVGQVVMVDsKKwkJCWdvdG8gb3V0Owor CQl9CisJfQorb3V0OgorCWlmIChyYykgeworCQlmb3IgKG4gPSAwOyBuIDwgbnVtX3BhcmFtczsg bisrKQorCQkJaWYgKGZkc1tuXSA+PSAwKQorCQkJCXRlZV9zaG1fcHV0X2ZkKGZkc1tuXSk7CisJ fQorCWtmcmVlKGZkcyk7CisJcmV0dXJuIHJjOworfQorCitzdGF0aWMgaW50IHRlZV9pb2N0bF9z dXBwX3JlY3Yoc3RydWN0IHRlZV9jb250ZXh0ICpjdHgsCisJCXN0cnVjdCB0ZWVfaW9jdGxfYnVm X2RhdGEgX191c2VyICp1YnVmKQoreworCWludCByYzsKKwlzdHJ1Y3QgdGVlX2lvY3RsX2J1Zl9k YXRhIGJ1ZjsKKwlzdHJ1Y3QgdGVlX2lvY2xfc3VwcF9yZWN2X2FyZyBfX3VzZXIgKnVhcmc7CisJ c3RydWN0IHRlZV9wYXJhbSAqcGFyYW1zOworCXN0cnVjdCB0ZWVfaW9jdGxfcGFyYW0gX191c2Vy ICp1cGFyYW1zOworCXUzMiBudW1fcGFyYW1zOworCXUzMiBmdW5jOworCisJaWYgKCFjdHgtPnRl ZWRldi0+ZGVzYy0+b3BzLT5zdXBwX3JlY3YpCisJCXJldHVybiAtRUlOVkFMOworCisJaWYgKGNv cHlfZnJvbV91c2VyKCZidWYsIHVidWYsIHNpemVvZihidWYpKSkKKwkJcmV0dXJuIC1FRkFVTFQ7 CisKKwlpZiAoYnVmLmJ1Zl9sZW4gPiBURUVfTUFYX0FSR19TSVpFIHx8CisJICAgIGJ1Zi5idWZf bGVuIDwgc2l6ZW9mKHN0cnVjdCB0ZWVfaW9jbF9zdXBwX3JlY3ZfYXJnKSkKKwkJcmV0dXJuIC1F SU5WQUw7CisKKwl1YXJnID0gKHN0cnVjdCB0ZWVfaW9jbF9zdXBwX3JlY3ZfYXJnIF9fdXNlciAq KSh1bnNpZ25lZCBsb25nKQorCQlidWYuYnVmX3B0cjsKKwlpZiAoZ2V0X3VzZXIobnVtX3BhcmFt cywgJnVhcmctPm51bV9wYXJhbXMpKQorCQlyZXR1cm4gLUVGQVVMVDsKKworCWlmIChzaXplb2Yo KnVhcmcpICsgVEVFX0lPQ1RMX1BBUkFNX1NJWkUobnVtX3BhcmFtcykgIT0gYnVmLmJ1Zl9sZW4p CisJCXJldHVybiAtRUlOVkFMOworCisJcGFyYW1zID0ga2NhbGxvYyhudW1fcGFyYW1zLCBzaXpl b2Yoc3RydWN0IHRlZV9wYXJhbSksIEdGUF9LRVJORUwpOworCWlmICghcGFyYW1zKQorCQlyZXR1 cm4gLUVOT01FTTsKKworCXJjID0gY3R4LT50ZWVkZXYtPmRlc2MtPm9wcy0+c3VwcF9yZWN2KGN0 eCwgJmZ1bmMsICZudW1fcGFyYW1zLCBwYXJhbXMpOworCWlmIChyYykKKwkJZ290byBvdXQ7CisK KwlpZiAocHV0X3VzZXIoZnVuYywgJnVhcmctPmZ1bmMpIHx8CisJICAgIHB1dF91c2VyKG51bV9w YXJhbXMsICZ1YXJnLT5udW1fcGFyYW1zKSkgeworCQlyYyA9IC1FRkFVTFQ7CisJCWdvdG8gb3V0 OworCX0KKworCXVwYXJhbXMgPSAoc3RydWN0IHRlZV9pb2N0bF9wYXJhbSBfX3VzZXIgKikodWFy ZyArIDEpOworCXJjID0gcGFyYW1zX3RvX3N1cHAodXBhcmFtcywgbnVtX3BhcmFtcywgcGFyYW1z KTsKK291dDoKKwlrZnJlZShwYXJhbXMpOworCXJldHVybiByYzsKK30KKworc3RhdGljIGludCBw YXJhbXNfZnJvbV9zdXBwKHN0cnVjdCB0ZWVfcGFyYW0gKnBhcmFtcywKKwkJc2l6ZV90IG51bV9w YXJhbXMsIHN0cnVjdCB0ZWVfaW9jdGxfcGFyYW0gX191c2VyICp1cGFyYW1zKQoreworCXNpemVf dCBuOworCisJZm9yIChuID0gMDsgbiA8IG51bV9wYXJhbXM7IG4rKykgeworCQlzdHJ1Y3QgdGVl X3BhcmFtICpwID0gcGFyYW1zICsgbjsKKwkJc3RydWN0IHRlZV9pb2N0bF9wYXJhbSBpcDsKKwor CQlpZiAoY29weV9mcm9tX3VzZXIoJmlwLCB1cGFyYW1zICsgbiwgc2l6ZW9mKGlwKSkpCisJCQly ZXR1cm4gLUVGQVVMVDsKKworCQkvKiBBbGwgdW51c2VkIGF0dHJpYnV0ZSBiaXRzIGhhcyB0byBi ZSB6ZXJvICovCisJCWlmIChpcC5hdHRyICYgflRFRV9JT0NUTF9QQVJBTV9BVFRSX1RZUEVfTUFT SykKKwkJCXJldHVybiAtRUlOVkFMOworCisJCXAtPmF0dHIgPSBpcC5hdHRyOworCQlzd2l0Y2gg KGlwLmF0dHIpIHsKKwkJY2FzZSBURUVfSU9DVExfUEFSQU1fQVRUUl9UWVBFX1ZBTFVFX09VVFBV VDoKKwkJY2FzZSBURUVfSU9DVExfUEFSQU1fQVRUUl9UWVBFX1ZBTFVFX0lOT1VUOgorCQkJLyog T25seSBvdXQgYW5kIGluL291dCB2YWx1ZXMgY2FuIGJlIHVwZGF0ZWQgKi8KKwkJCXAtPnUudmFs dWUuYSA9IGlwLnUudmFsdWUuYTsKKwkJCXAtPnUudmFsdWUuYiA9IGlwLnUudmFsdWUuYjsKKwkJ CXAtPnUudmFsdWUuYyA9IGlwLnUudmFsdWUuYzsKKwkJCWJyZWFrOworCQljYXNlIFRFRV9JT0NU TF9QQVJBTV9BVFRSX1RZUEVfTUVNUkVGX09VVFBVVDoKKwkJY2FzZSBURUVfSU9DVExfUEFSQU1f QVRUUl9UWVBFX01FTVJFRl9JTk9VVDoKKwkJCS8qCisJCQkgKiBPbmx5IHRoZSBzaXplIG9mIHRo ZSBtZW1yZWYgY2FuIGJlIHVwZGF0ZWQuCisJCQkgKiBTaW5jZSB3ZSBkb24ndCBoYXZlIGFjY2Vz cyB0byB0aGUgb3JpZ2luYWwKKwkJCSAqIHBhcmFtZXRlcnMgaGVyZSwgb25seSBzdG9yZSB0aGUg c3VwcGxpZWQgc2l6ZS4KKwkJCSAqIFRoZSBkcml2ZXIgd2lsbCBjb3B5IHRoZSB1cGRhdGVkIHNp emUgaW50byB0aGUKKwkJCSAqIG9yaWdpbmFsIHBhcmFtZXRlcnMuCisJCQkgKi8KKwkJCXAtPnUu bWVtcmVmLnNobSA9IE5VTEw7CisJCQlwLT51Lm1lbXJlZi5zaG1fb2ZmcyA9IDA7CisJCQlwLT51 Lm1lbXJlZi5zaXplID0gaXAudS5tZW1yZWYuc2l6ZTsKKwkJCWJyZWFrOworCQlkZWZhdWx0Ogor CQkJbWVtc2V0KCZwLT51LCAwLCBzaXplb2YocC0+dSkpOworCQkJYnJlYWs7CisJCX0KKwl9CisJ cmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgdGVlX2lvY3RsX3N1cHBfc2VuZChzdHJ1Y3QgdGVl X2NvbnRleHQgKmN0eCwKKwkJc3RydWN0IHRlZV9pb2N0bF9idWZfZGF0YSBfX3VzZXIgKnVidWYp Cit7CisJbG9uZyByYzsKKwlzdHJ1Y3QgdGVlX2lvY3RsX2J1Zl9kYXRhIGJ1ZjsKKwlzdHJ1Y3Qg dGVlX2lvY2xfc3VwcF9zZW5kX2FyZyBfX3VzZXIgKnVhcmc7CisJc3RydWN0IHRlZV9wYXJhbSAq cGFyYW1zOworCXN0cnVjdCB0ZWVfaW9jdGxfcGFyYW0gX191c2VyICp1cGFyYW1zOworCXUzMiBu dW1fcGFyYW1zOworCXUzMiByZXQ7CisKKwkvKiBOb3QgdmFsaWQgZm9yIHRoaXMgZHJpdmVyICov CisJaWYgKCFjdHgtPnRlZWRldi0+ZGVzYy0+b3BzLT5zdXBwX3NlbmQpCisJCXJldHVybiAtRUlO VkFMOworCisJaWYgKGNvcHlfZnJvbV91c2VyKCZidWYsIHVidWYsIHNpemVvZihidWYpKSkKKwkJ cmV0dXJuIC1FRkFVTFQ7CisKKwlpZiAoYnVmLmJ1Zl9sZW4gPiBURUVfTUFYX0FSR19TSVpFIHx8 CisJICAgIGJ1Zi5idWZfbGVuIDwgc2l6ZW9mKHN0cnVjdCB0ZWVfaW9jbF9zdXBwX3NlbmRfYXJn KSkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwl1YXJnID0gKHN0cnVjdCB0ZWVfaW9jbF9zdXBwX3Nl bmRfYXJnIF9fdXNlciAqKSh1bnNpZ25lZCBsb25nKQorCQlidWYuYnVmX3B0cjsKKwlpZiAoZ2V0 X3VzZXIocmV0LCAmdWFyZy0+cmV0KSB8fAorCSAgICBnZXRfdXNlcihudW1fcGFyYW1zLCAmdWFy Zy0+bnVtX3BhcmFtcykpCisJCXJldHVybiAtRUZBVUxUOworCisJaWYgKHNpemVvZigqdWFyZykg KyBURUVfSU9DVExfUEFSQU1fU0laRShudW1fcGFyYW1zKSA+IGJ1Zi5idWZfbGVuKQorCQlyZXR1 cm4gLUVJTlZBTDsKKworCXBhcmFtcyA9IGtjYWxsb2MobnVtX3BhcmFtcywgc2l6ZW9mKHN0cnVj dCB0ZWVfcGFyYW0pLCBHRlBfS0VSTkVMKTsKKwlpZiAoIXBhcmFtcykKKwkJcmV0dXJuIC1FTk9N RU07CisKKwl1cGFyYW1zID0gKHN0cnVjdCB0ZWVfaW9jdGxfcGFyYW0gX191c2VyICopKHVhcmcg KyAxKTsKKwlyYyA9IHBhcmFtc19mcm9tX3N1cHAocGFyYW1zLCBudW1fcGFyYW1zLCB1cGFyYW1z KTsKKwlpZiAocmMpCisJCWdvdG8gb3V0OworCisJcmMgPSBjdHgtPnRlZWRldi0+ZGVzYy0+b3Bz LT5zdXBwX3NlbmQoY3R4LCByZXQsIG51bV9wYXJhbXMsIHBhcmFtcyk7CitvdXQ6CisJa2ZyZWUo cGFyYW1zKTsKKwlyZXR1cm4gcmM7Cit9CisKKworc3RhdGljIGxvbmcgdGVlX2lvY3RsKHN0cnVj dCBmaWxlICpmaWxwLCB1bnNpZ25lZCBpbnQgY21kLCB1bnNpZ25lZCBsb25nIGFyZykKK3sKKwlz dHJ1Y3QgdGVlX2NvbnRleHQgKmN0eCA9IGZpbHAtPnByaXZhdGVfZGF0YTsKKwl2b2lkIF9fdXNl ciAqdWFyZyA9ICh2b2lkIF9fdXNlciAqKWFyZzsKKworCXN3aXRjaCAoY21kKSB7CisJY2FzZSBU RUVfSU9DX1ZFUlNJT046CisJCXJldHVybiB0ZWVfaW9jdGxfdmVyc2lvbihjdHgsIHVhcmcpOwor CWNhc2UgVEVFX0lPQ19TSE1fQUxMT0M6CisJCXJldHVybiB0ZWVfaW9jdGxfc2htX2FsbG9jKGN0 eCwgdWFyZyk7CisJY2FzZSBURUVfSU9DX09QRU5fU0VTU0lPTjoKKwkJcmV0dXJuIHRlZV9pb2N0 bF9vcGVuX3Nlc3Npb24oY3R4LCB1YXJnKTsKKwljYXNlIFRFRV9JT0NfSU5WT0tFOgorCQlyZXR1 cm4gdGVlX2lvY3RsX2ludm9rZShjdHgsIHVhcmcpOworCWNhc2UgVEVFX0lPQ19DQU5DRUw6CisJ CXJldHVybiB0ZWVfaW9jdGxfY2FuY2VsKGN0eCwgdWFyZyk7CisJY2FzZSBURUVfSU9DX0NMT1NF X1NFU1NJT046CisJCXJldHVybiB0ZWVfaW9jdGxfY2xvc2Vfc2Vzc2lvbihjdHgsIHVhcmcpOwor CWNhc2UgVEVFX0lPQ19TVVBQTF9SRUNWOgorCQlyZXR1cm4gdGVlX2lvY3RsX3N1cHBfcmVjdihj dHgsIHVhcmcpOworCWNhc2UgVEVFX0lPQ19TVVBQTF9TRU5EOgorCQlyZXR1cm4gdGVlX2lvY3Rs X3N1cHBfc2VuZChjdHgsIHVhcmcpOworCWRlZmF1bHQ6CisJCXJldHVybiAtRUlOVkFMOworCX0K K30KKworc3RhdGljIGNvbnN0IHN0cnVjdCBmaWxlX29wZXJhdGlvbnMgdGVlX2ZvcHMgPSB7CisJ Lm9wZW4gPSB0ZWVfb3BlbiwKKwkucmVsZWFzZSA9IHRlZV9yZWxlYXNlLAorCS51bmxvY2tlZF9p b2N0bCA9IHRlZV9pb2N0bCwKKwkuY29tcGF0X2lvY3RsID0gdGVlX2lvY3RsLAorfTsKKworc3Rh dGljIHZvaWQgdGVlX3JlbGVhc2VfZGV2aWNlKHN0cnVjdCBkZXZpY2UgKmRldikKK3sKKwlzdHJ1 Y3QgdGVlX2RldmljZSAqdGVlZGV2ID0gY29udGFpbmVyX29mKGRldiwgc3RydWN0IHRlZV9kZXZp Y2UsIGRldik7CisKKwlzcGluX2xvY2soJmRyaXZlcl9sb2NrKTsKKwljbGVhcl9iaXQodGVlZGV2 LT5pZCwgZGV2X21hc2spOworCXNwaW5fdW5sb2NrKCZkcml2ZXJfbG9jayk7CisJbXV0ZXhfZGVz dHJveSgmdGVlZGV2LT5tdXRleCk7CisJa2ZyZWUodGVlZGV2KTsKK30KKworc3RydWN0IHRlZV9k ZXZpY2UgKnRlZV9kZXZpY2VfYWxsb2MoY29uc3Qgc3RydWN0IHRlZV9kZXNjICp0ZWVkZXNjLAor CQkJc3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3QgdGVlX3NobV9wb29sICpwb29sLAorCQkJdm9p ZCAqZHJpdmVyX2RhdGEpCit7CisJc3RydWN0IHRlZV9kZXZpY2UgKnRlZWRldjsKKwl2b2lkICpy ZXQ7CisJaW50IHJjOworCWludCBvZmZzID0gMDsKKworCWlmICghdGVlZGVzYyB8fCAhdGVlZGVz Yy0+bmFtZSB8fCAhdGVlZGVzYy0+b3BzIHx8CisJICAgICF0ZWVkZXNjLT5vcHMtPmdldF92ZXJz aW9uIHx8ICF0ZWVkZXNjLT5vcHMtPm9wZW4gfHwKKwkgICAgIXRlZWRlc2MtPm9wcy0+cmVsZWFz ZSB8fCAhZGV2IHx8ICFwb29sKQorCQlyZXR1cm4gRVJSX1BUUigtRUlOVkFMKTsKKworCXRlZWRl diA9IGt6YWxsb2Moc2l6ZW9mKCp0ZWVkZXYpLCBHRlBfS0VSTkVMKTsKKwlpZiAoIXRlZWRldikg eworCQlyZXQgPSBFUlJfUFRSKC1FTk9NRU0pOworCQlnb3RvIGVycjsKKwl9CisKKwlpZiAodGVl ZGVzYy0+ZmxhZ3MgJiBURUVfREVTQ19QUklWSUxFR0VEKQorCQlvZmZzID0gVEVFX05VTV9ERVZJ Q0VTIC8gMjsKKworCXNwaW5fbG9jaygmZHJpdmVyX2xvY2spOworCXRlZWRldi0+aWQgPSBmaW5k X25leHRfemVyb19iaXQoZGV2X21hc2ssIFRFRV9OVU1fREVWSUNFUywgb2Zmcyk7CisJaWYgKHRl ZWRldi0+aWQgPCBURUVfTlVNX0RFVklDRVMpCisJCXNldF9iaXQodGVlZGV2LT5pZCwgZGV2X21h c2spOworCXNwaW5fdW5sb2NrKCZkcml2ZXJfbG9jayk7CisKKwlpZiAodGVlZGV2LT5pZCA+PSBU RUVfTlVNX0RFVklDRVMpIHsKKwkJcmV0ID0gRVJSX1BUUigtRU5PTUVNKTsKKwkJZ290byBlcnI7 CisJfQorCisJc25wcmludGYodGVlZGV2LT5uYW1lLCBzaXplb2YodGVlZGV2LT5uYW1lKSwgInRl ZSVzJWQiLAorCQkgdGVlZGVzYy0+ZmxhZ3MgJiBURUVfREVTQ19QUklWSUxFR0VEID8gInByaXYi IDogIiIsCisJCSB0ZWVkZXYtPmlkIC0gb2Zmcyk7CisKKwl0ZWVkZXYtPmRldi5jbGFzcyA9IHRl ZV9jbGFzczsKKwl0ZWVkZXYtPmRldi5yZWxlYXNlID0gdGVlX3JlbGVhc2VfZGV2aWNlOworCXRl ZWRldi0+ZGV2LnBhcmVudCA9IGRldjsKKwl0ZWVkZXYtPmRldi5kZXZ0ID0gTUtERVYoTUFKT1Io dGVlX2RldnQpLCB0ZWVkZXYtPmlkKTsKKworCXJjID0gZGV2X3NldF9uYW1lKCZ0ZWVkZXYtPmRl diwgIiVzIiwgdGVlZGV2LT5uYW1lKTsKKwlpZiAocmMpIHsKKwkJcmV0ID0gRVJSX1BUUihyYyk7 CisJCWdvdG8gZXJyOworCX0KKworCWNkZXZfaW5pdCgmdGVlZGV2LT5jZGV2LCAmdGVlX2ZvcHMp OworCXRlZWRldi0+Y2Rldi5vd25lciA9IHRlZWRlc2MtPm93bmVyOworCXRlZWRldi0+Y2Rldi5r b2JqLnBhcmVudCA9ICZ0ZWVkZXYtPmRldi5rb2JqOworCisJZGV2X3NldF9kcnZkYXRhKCZ0ZWVk ZXYtPmRldiwgZHJpdmVyX2RhdGEpOworCWRldmljZV9pbml0aWFsaXplKCZ0ZWVkZXYtPmRldik7 CisKKwkvKiAxIGFzIHRlZV9kZXZpY2VfdW5yZWdpc3RlcigpIGRvZXMgb25lIGZpbmFsIHRlZV9k ZXZpY2VfcHV0KCkgKi8KKwl0ZWVkZXYtPm51bV91c2VycyA9IDE7CisJaW5pdF9jb21wbGV0aW9u KCZ0ZWVkZXYtPmNfbm9fdXNlcnMpOworCW11dGV4X2luaXQoJnRlZWRldi0+bXV0ZXgpOworCisJ dGVlZGV2LT5kZXNjID0gdGVlZGVzYzsKKwl0ZWVkZXYtPnBvb2wgPSBwb29sOworCUlOSVRfTElT VF9IRUFEKCZ0ZWVkZXYtPmxpc3Rfc2htKTsKKworCXJldHVybiB0ZWVkZXY7CitlcnI6CisJZGV2 X2VycihkZXYsICJjb3VsZCBub3QgcmVnaXN0ZXIgJXMgZHJpdmVyXG4iLAorCQl0ZWVkZXNjLT5m bGFncyAmIFRFRV9ERVNDX1BSSVZJTEVHRUQgPyAicHJpdmlsZWdlZCIgOiAiY2xpZW50Iik7CisJ aWYgKHRlZWRldiAmJiB0ZWVkZXYtPmlkIDwgVEVFX05VTV9ERVZJQ0VTKSB7CisJCXNwaW5fbG9j aygmZHJpdmVyX2xvY2spOworCQljbGVhcl9iaXQodGVlZGV2LT5pZCwgZGV2X21hc2spOworCQlz cGluX3VubG9jaygmZHJpdmVyX2xvY2spOworCX0KKwlrZnJlZSh0ZWVkZXYpOworCXJldHVybiBy ZXQ7Cit9CitFWFBPUlRfU1lNQk9MX0dQTCh0ZWVfZGV2aWNlX2FsbG9jKTsKKworc3RhdGljIHNz aXplX3QgaW1wbGVtZW50YXRpb25faWRfc2hvdyhzdHJ1Y3QgZGV2aWNlICpkZXYsCisJCQlzdHJ1 Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQoreworCXN0cnVjdCB0ZWVfZGV2 aWNlICp0ZWVkZXYgPSBjb250YWluZXJfb2YoZGV2LCBzdHJ1Y3QgdGVlX2RldmljZSwgZGV2KTsK KwlzdHJ1Y3QgdGVlX2lvY3RsX3ZlcnNpb25fZGF0YSB2ZXJzOworCisJdGVlZGV2LT5kZXNjLT5v cHMtPmdldF92ZXJzaW9uKHRlZWRldiwgJnZlcnMpOworCXJldHVybiBzY25wcmludGYoYnVmLCBQ QUdFX1NJWkUsICIlZFxuIiwgdmVycy5pbXBsX2lkKTsKK30KK3N0YXRpYyBERVZJQ0VfQVRUUl9S TyhpbXBsZW1lbnRhdGlvbl9pZCk7CisKK3N0YXRpYyBzdHJ1Y3QgYXR0cmlidXRlICp0ZWVfZGV2 X2F0dHJzW10gPSB7CisJJmRldl9hdHRyX2ltcGxlbWVudGF0aW9uX2lkLmF0dHIsCisJTlVMTAor fTsKKworc3RhdGljIGNvbnN0IHN0cnVjdCBhdHRyaWJ1dGVfZ3JvdXAgdGVlX2Rldl9ncm91cCA9 IHsKKwkuYXR0cnMgPSB0ZWVfZGV2X2F0dHJzLAorfTsKKworaW50IHRlZV9kZXZpY2VfcmVnaXN0 ZXIoc3RydWN0IHRlZV9kZXZpY2UgKnRlZWRldikKK3sKKwlpbnQgcmM7CisKKwkvKgorCSAqIElm IHRoZSB0ZWVkZXYgYWxyZWFkeSBpcyByZWdpc3RlcmVkLCBkb24ndCBkbyBpdCBhZ2Fpbi4gSXQn cworCSAqIG9idmlvdXNseSBhbiBlcnJvciB0byB0cnkgdG8gcmVnaXN0ZXIgdHdpY2UsIGJ1dCBp ZiB3ZSByZXR1cm4KKwkgKiBhbiBlcnJvciB3ZSdsbCBmb3JjZSB0aGUgZHJpdmVyIHRvIHJlbW92 ZSB0aGUgdGVlZGV2LgorCSAqLworCWlmICh0ZWVkZXYtPmZsYWdzICYgVEVFX0RFVklDRV9GTEFH X1JFR0lTVEVSRUQpIHsKKwkJZGV2X2VycigmdGVlZGV2LT5kZXYsICJhdHRlbXB0IHRvIHJlZ2lz dGVyIHR3aWNlXG4iKTsKKwkJcmV0dXJuIDA7CisJfQorCisJcmMgPSBjZGV2X2FkZCgmdGVlZGV2 LT5jZGV2LCB0ZWVkZXYtPmRldi5kZXZ0LCAxKTsKKwlpZiAocmMpIHsKKwkJZGV2X2VycigmdGVl ZGV2LT5kZXYsCisJCQkidW5hYmxlIHRvIGNkZXZfYWRkKCkgJXMsIG1ham9yICVkLCBtaW5vciAl ZCwgZXJyPSVkXG4iLAorCQkJdGVlZGV2LT5uYW1lLCBNQUpPUih0ZWVkZXYtPmRldi5kZXZ0KSwK KwkJCU1JTk9SKHRlZWRldi0+ZGV2LmRldnQpLCByYyk7CisJCXJldHVybiByYzsKKwl9CisKKwly YyA9IGRldmljZV9hZGQoJnRlZWRldi0+ZGV2KTsKKwlpZiAocmMpIHsKKwkJZGV2X2VycigmdGVl ZGV2LT5kZXYsCisJCQkidW5hYmxlIHRvIGRldmljZV9hZGQoKSAlcywgbWFqb3IgJWQsIG1pbm9y ICVkLCBlcnI9JWRcbiIsCisJCQl0ZWVkZXYtPm5hbWUsIE1BSk9SKHRlZWRldi0+ZGV2LmRldnQp LAorCQkJTUlOT1IodGVlZGV2LT5kZXYuZGV2dCksIHJjKTsKKwkJZ290byBlcnJfZGV2aWNlX2Fk ZDsKKwl9CisKKwlyYyA9IHN5c2ZzX2NyZWF0ZV9ncm91cCgmdGVlZGV2LT5kZXYua29iaiwgJnRl ZV9kZXZfZ3JvdXApOworCWlmIChyYykgeworCQlkZXZfZXJyKCZ0ZWVkZXYtPmRldiwKKwkJCSJm YWlsZWQgdG8gY3JlYXRlIHN5c2ZzIGF0dHJpYnV0ZXMsIGVycj0lZFxuIiwgcmMpOworCQlnb3Rv IGVycl9zeXNmc19jcmVhdGVfZ3JvdXA7CisJfQorCisJdGVlZGV2LT5mbGFncyB8PSBURUVfREVW SUNFX0ZMQUdfUkVHSVNURVJFRDsKKwlyZXR1cm4gMDsKKworZXJyX3N5c2ZzX2NyZWF0ZV9ncm91 cDoKKwlkZXZpY2VfZGVsKCZ0ZWVkZXYtPmRldik7CitlcnJfZGV2aWNlX2FkZDoKKwljZGV2X2Rl bCgmdGVlZGV2LT5jZGV2KTsKKwlyZXR1cm4gcmM7CisKK30KK0VYUE9SVF9TWU1CT0xfR1BMKHRl ZV9kZXZpY2VfcmVnaXN0ZXIpOworCit2b2lkIHRlZV9kZXZpY2VfcHV0KHN0cnVjdCB0ZWVfZGV2 aWNlICp0ZWVkZXYpCit7CisJbXV0ZXhfbG9jaygmdGVlZGV2LT5tdXRleCk7CisJLyogU2hvdWxk bid0IHB1dCBpbiB0aGlzIHN0YXRlICovCisJaWYgKCFXQVJOX09OKCF0ZWVkZXYtPmRlc2MpKSB7 CisJCXRlZWRldi0+bnVtX3VzZXJzLS07CisJCWlmICghdGVlZGV2LT5udW1fdXNlcnMpIHsKKwkJ CXRlZWRldi0+ZGVzYyA9IE5VTEw7CisJCQljb21wbGV0ZSgmdGVlZGV2LT5jX25vX3VzZXJzKTsK KwkJfQorCX0KKwltdXRleF91bmxvY2soJnRlZWRldi0+bXV0ZXgpOworfQorCitib29sIHRlZV9k ZXZpY2VfZ2V0KHN0cnVjdCB0ZWVfZGV2aWNlICp0ZWVkZXYpCit7CisJbXV0ZXhfbG9jaygmdGVl ZGV2LT5tdXRleCk7CisJaWYgKCF0ZWVkZXYtPmRlc2MpIHsKKwkJbXV0ZXhfdW5sb2NrKCZ0ZWVk ZXYtPm11dGV4KTsKKwkJcmV0dXJuIGZhbHNlOworCX0KKwl0ZWVkZXYtPm51bV91c2VycysrOwor CW11dGV4X3VubG9jaygmdGVlZGV2LT5tdXRleCk7CisJcmV0dXJuIHRydWU7Cit9CisKK3ZvaWQg dGVlX2RldmljZV91bnJlZ2lzdGVyKHN0cnVjdCB0ZWVfZGV2aWNlICp0ZWVkZXYpCit7CisJaWYg KCF0ZWVkZXYpCisJCXJldHVybjsKKworCWlmICh0ZWVkZXYtPmZsYWdzICYgVEVFX0RFVklDRV9G TEFHX1JFR0lTVEVSRUQpIHsKKwkJc3lzZnNfcmVtb3ZlX2dyb3VwKCZ0ZWVkZXYtPmRldi5rb2Jq LCAmdGVlX2Rldl9ncm91cCk7CisJCWNkZXZfZGVsKCZ0ZWVkZXYtPmNkZXYpOworCQlkZXZpY2Vf ZGVsKCZ0ZWVkZXYtPmRldik7CisJfQorCisJdGVlX2RldmljZV9wdXQodGVlZGV2KTsKKwl3YWl0 X2Zvcl9jb21wbGV0aW9uKCZ0ZWVkZXYtPmNfbm9fdXNlcnMpOworCisJLyoKKwkgKiBObyBuZWVk IHRvIHRha2UgYSBtdXRleCBhbnkgbG9uZ2VyIG5vdyBzaW5jZSB0ZWVkZXYtPmRlc2Mgd2FzCisJ ICogc2V0IHRvIE5VTEwgYmVmb3JlIHRlZWRldi0+Y19ub191c2VycyB3YXMgY29tcGxldGVkLgor CSAqLworCisJdGVlZGV2LT5wb29sID0gTlVMTDsKKworCXB1dF9kZXZpY2UoJnRlZWRldi0+ZGV2 KTsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKHRlZV9kZXZpY2VfdW5yZWdpc3Rlcik7CisKK3ZvaWQg KnRlZV9nZXRfZHJ2ZGF0YShzdHJ1Y3QgdGVlX2RldmljZSAqdGVlZGV2KQoreworCXJldHVybiBk ZXZfZ2V0X2RydmRhdGEoJnRlZWRldi0+ZGV2KTsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKHRlZV9n ZXRfZHJ2ZGF0YSk7CisKK3N0YXRpYyBpbnQgX19pbml0IHRlZV9pbml0KHZvaWQpCit7CisJaW50 IHJjOworCisJdGVlX2NsYXNzID0gY2xhc3NfY3JlYXRlKFRISVNfTU9EVUxFLCAidGVlIik7CisJ aWYgKElTX0VSUih0ZWVfY2xhc3MpKSB7CisJCXByX2VycigiY291bGRuJ3QgY3JlYXRlIGNsYXNz XG4iKTsKKwkJcmV0dXJuIFBUUl9FUlIodGVlX2NsYXNzKTsKKwl9CisKKwlyYyA9IGFsbG9jX2No cmRldl9yZWdpb24oJnRlZV9kZXZ0LCAwLCBURUVfTlVNX0RFVklDRVMsICJ0ZWUiKTsKKwlpZiAo cmMgPCAwKSB7CisJCXByX2VycigiZmFpbGVkIHRvIGFsbG9jYXRlIGNoYXIgZGV2IHJlZ2lvblxu Iik7CisJCWNsYXNzX2Rlc3Ryb3kodGVlX2NsYXNzKTsKKwkJdGVlX2NsYXNzID0gTlVMTDsKKwl9 CisKKwlyZXR1cm4gcmM7Cit9CisKK3N1YnN5c19pbml0Y2FsbCh0ZWVfaW5pdCk7CmRpZmYgLS1n aXQgYS9kcml2ZXJzL3RlZS90ZWVfcHJpdmF0ZS5oIGIvZHJpdmVycy90ZWUvdGVlX3ByaXZhdGUu aApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwLi5kMzJhYzU0Ci0tLSAvZGV2L251 bGwKKysrIGIvZHJpdmVycy90ZWUvdGVlX3ByaXZhdGUuaApAQCAtMCwwICsxLDgwIEBACisvKgor ICogQ29weXJpZ2h0IChjKSAyMDE1LCBMaW5hcm8gTGltaXRlZAorICoKKyAqIFRoaXMgc29mdHdh cmUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMK KyAqIExpY2Vuc2UgdmVyc2lvbiAyLCBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUg Rm91bmRhdGlvbiwgYW5kCisgKiBtYXkgYmUgY29waWVkLCBkaXN0cmlidXRlZCwgYW5kIG1vZGlm aWVkIHVuZGVyIHRob3NlIHRlcm1zLgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRl ZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLAorICogYnV0IFdJVEhPVVQgQU5Z IFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YKKyAqIE1FUkNI QU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUK KyAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCisgKgorICov CisjaWZuZGVmIFRFRV9QUklWQVRFX0gKKyNkZWZpbmUgVEVFX1BSSVZBVEVfSAorCisjaW5jbHVk ZSA8bGludXgvdHlwZXMuaD4KKyNpbmNsdWRlIDxsaW51eC9kZXZpY2UuaD4KKyNpbmNsdWRlIDxs aW51eC9jZGV2Lmg+CisjaW5jbHVkZSA8bGludXgvY29tcGxldGlvbi5oPgorI2luY2x1ZGUgPGxp bnV4L211dGV4Lmg+CisjaW5jbHVkZSA8bGludXgva3JlZi5oPgorCitzdHJ1Y3QgdGVlX2Rldmlj ZTsKKworc3RydWN0IHRlZV9zaG0geworCXN0cnVjdCBsaXN0X2hlYWQgbGlzdF9ub2RlOworCXN0 cnVjdCB0ZWVfZGV2aWNlICp0ZWVkZXY7CisJcGh5c19hZGRyX3QgcGFkZHI7CisJdm9pZCAqa2Fk ZHI7CisJc2l6ZV90IHNpemU7CisJc3RydWN0IGRtYV9idWYgKmRtYWJ1ZjsKKwl1MzIgZmxhZ3M7 Cit9OworCitzdHJ1Y3QgdGVlX3NobV9wb29sX21ncjsKK3N0cnVjdCB0ZWVfc2htX3Bvb2xfbWdy X29wcyB7CisJaW50ICgqYWxsb2MpKHN0cnVjdCB0ZWVfc2htX3Bvb2xfbWdyICpwb29sbWdyLCBz dHJ1Y3QgdGVlX3NobSAqc2htLAorCQkgICAgIHNpemVfdCBzaXplKTsKKwl2b2lkICgqZnJlZSko c3RydWN0IHRlZV9zaG1fcG9vbF9tZ3IgKnBvb2xtZ3IsIHN0cnVjdCB0ZWVfc2htICpzaG0pOwor fTsKKworc3RydWN0IHRlZV9zaG1fcG9vbF9tZ3IgeworCWNvbnN0IHN0cnVjdCB0ZWVfc2htX3Bv b2xfbWdyX29wcyAqb3BzOworCXZvaWQgKnByaXZhdGVfZGF0YTsKK307CisKK3N0cnVjdCB0ZWVf c2htX3Bvb2wgeworCXN0cnVjdCB0ZWVfc2htX3Bvb2xfbWdyIHByaXZhdGVfbWdyOworCXN0cnVj dCB0ZWVfc2htX3Bvb2xfbWdyIGRtYV9idWZfbWdyOworCXZvaWQgKCpkZXN0cm95KShzdHJ1Y3Qg dGVlX3NobV9wb29sICpwb29sKTsKKwl2b2lkICpwcml2YXRlX2RhdGE7Cit9OworCisjZGVmaW5l IFRFRV9ERVZJQ0VfRkxBR19SRUdJU1RFUkVECTB4MQorI2RlZmluZSBURUVfTUFYX0RFVl9OQU1F X0xFTgkJMzIKKworc3RydWN0IHRlZV9kZXZpY2UgeworCWNoYXIgbmFtZVtURUVfTUFYX0RFVl9O QU1FX0xFTl07CisJY29uc3Qgc3RydWN0IHRlZV9kZXNjICpkZXNjOworCWludCBpZDsKKwl1bnNp Z25lZCBmbGFnczsKKworCXN0cnVjdCBkZXZpY2UgZGV2OworCXN0cnVjdCBjZGV2IGNkZXY7CisK KwlzaXplX3QgbnVtX3VzZXJzOworCXN0cnVjdCBjb21wbGV0aW9uIGNfbm9fdXNlcnM7CisJc3Ry dWN0IG11dGV4IG11dGV4OworCisJc3RydWN0IGxpc3RfaGVhZCBsaXN0X3NobTsKKwlzdHJ1Y3Qg dGVlX3NobV9wb29sICpwb29sOworfTsKKworaW50IHRlZV9zaG1faW5pdCh2b2lkKTsKKworYm9v bCB0ZWVfZGV2aWNlX2dldChzdHJ1Y3QgdGVlX2RldmljZSAqdGVlZGV2KTsKK3ZvaWQgdGVlX2Rl dmljZV9wdXQoc3RydWN0IHRlZV9kZXZpY2UgKnRlZWRldik7CisKKyNlbmRpZiAvKlRFRV9QUklW QVRFX0gqLwpkaWZmIC0tZ2l0IGEvZHJpdmVycy90ZWUvdGVlX3NobS5jIGIvZHJpdmVycy90ZWUv dGVlX3NobS5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAuLjY3MzJlNzcKLS0t IC9kZXYvbnVsbAorKysgYi9kcml2ZXJzL3RlZS90ZWVfc2htLmMKQEAgLTAsMCArMSwzMjQgQEAK Ky8qCisgKiBDb3B5cmlnaHQgKGMpIDIwMTUsIExpbmFybyBMaW1pdGVkCisgKgorICogVGhpcyBz b2Z0d2FyZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1 YmxpYworICogTGljZW5zZSB2ZXJzaW9uIDIsIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0 d2FyZSBGb3VuZGF0aW9uLCBhbmQKKyAqIG1heSBiZSBjb3BpZWQsIGRpc3RyaWJ1dGVkLCBhbmQg bW9kaWZpZWQgdW5kZXIgdGhvc2UgdGVybXMuCisgKgorICogVGhpcyBwcm9ncmFtIGlzIGRpc3Ry aWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCisgKiBidXQgV0lUSE9V VCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgorICog TUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2Vl IHRoZQorICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KKyAq CisgKi8KKyNpbmNsdWRlIDxsaW51eC9kZXZpY2UuaD4KKyNpbmNsdWRlIDxsaW51eC9mZHRhYmxl Lmg+CisjaW5jbHVkZSA8bGludXgvc2NoZWQuaD4KKyNpbmNsdWRlIDxsaW51eC9kbWEtYnVmLmg+ CisjaW5jbHVkZSA8bGludXgvc2xhYi5oPgorI2luY2x1ZGUgPGxpbnV4L3RlZV9kcnYuaD4KKyNp bmNsdWRlICJ0ZWVfcHJpdmF0ZS5oIgorCitzdGF0aWMgdm9pZCB0ZWVfc2htX3JlbGVhc2Uoc3Ry dWN0IHRlZV9zaG0gKnNobSkKK3sKKwlzdHJ1Y3QgdGVlX2RldmljZSAqdGVlZGV2ID0gc2htLT50 ZWVkZXY7CisJc3RydWN0IHRlZV9zaG1fcG9vbF9tZ3IgKnBvb2xtOworCisJbXV0ZXhfbG9jaygm dGVlZGV2LT5tdXRleCk7CisJbGlzdF9kZWwoJnNobS0+bGlzdF9ub2RlKTsKKwltdXRleF91bmxv Y2soJnRlZWRldi0+bXV0ZXgpOworCisJaWYgKHNobS0+ZmxhZ3MgJiBURUVfU0hNX0RNQV9CVUYp CisJCXBvb2xtID0gJnRlZWRldi0+cG9vbC0+ZG1hX2J1Zl9tZ3I7CisJZWxzZQorCQlwb29sbSA9 ICZ0ZWVkZXYtPnBvb2wtPnByaXZhdGVfbWdyOworCisJcG9vbG0tPm9wcy0+ZnJlZShwb29sbSwg c2htKTsKKwlrZnJlZShzaG0pOworCisJdGVlX2RldmljZV9wdXQodGVlZGV2KTsKK30KKworc3Rh dGljIHN0cnVjdCBzZ190YWJsZSAqdGVlX3NobV9vcF9tYXBfZG1hX2J1ZihzdHJ1Y3QgZG1hX2J1 Zl9hdHRhY2htZW50CisJCQkqYXR0YWNoLCBlbnVtIGRtYV9kYXRhX2RpcmVjdGlvbiBkaXIpCit7 CisJcmV0dXJuIE5VTEw7Cit9CisKK3N0YXRpYyB2b2lkIHRlZV9zaG1fb3BfdW5tYXBfZG1hX2J1 ZihzdHJ1Y3QgZG1hX2J1Zl9hdHRhY2htZW50ICphdHRhY2gsCisJCQlzdHJ1Y3Qgc2dfdGFibGUg KnRhYmxlLCBlbnVtIGRtYV9kYXRhX2RpcmVjdGlvbiBkaXIpCit7Cit9CisKK3N0YXRpYyB2b2lk IHRlZV9zaG1fb3BfcmVsZWFzZShzdHJ1Y3QgZG1hX2J1ZiAqZG1hYnVmKQoreworCXN0cnVjdCB0 ZWVfc2htICpzaG0gPSBkbWFidWYtPnByaXY7CisKKwl0ZWVfc2htX3JlbGVhc2Uoc2htKTsKK30K Kworc3RhdGljIHZvaWQgKnRlZV9zaG1fb3Bfa21hcF9hdG9taWMoc3RydWN0IGRtYV9idWYgKmRt YWJ1ZiwKKwkJCXVuc2lnbmVkIGxvbmcgcGdudW0pCit7CisJcmV0dXJuIE5VTEw7Cit9CisKK3N0 YXRpYyB2b2lkICp0ZWVfc2htX29wX2ttYXAoc3RydWN0IGRtYV9idWYgKmRtYWJ1ZiwgdW5zaWdu ZWQgbG9uZyBwZ251bSkKK3sKKwlyZXR1cm4gTlVMTDsKK30KKworc3RhdGljIGludCB0ZWVfc2ht X29wX21tYXAoc3RydWN0IGRtYV9idWYgKmRtYWJ1ZiwKKwkJCXN0cnVjdCB2bV9hcmVhX3N0cnVj dCAqdm1hKQoreworCXN0cnVjdCB0ZWVfc2htICpzaG0gPSBkbWFidWYtPnByaXY7CisJc2l6ZV90 IHNpemUgPSB2bWEtPnZtX2VuZCAtIHZtYS0+dm1fc3RhcnQ7CisKKwlyZXR1cm4gcmVtYXBfcGZu X3JhbmdlKHZtYSwgdm1hLT52bV9zdGFydCwgc2htLT5wYWRkciA+PiBQQUdFX1NISUZULAorCQkJ ICAgICAgIHNpemUsIHZtYS0+dm1fcGFnZV9wcm90KTsKK30KKworc3RhdGljIHN0cnVjdCBkbWFf YnVmX29wcyB0ZWVfc2htX2RtYV9idWZfb3BzID0geworCS5tYXBfZG1hX2J1ZiA9IHRlZV9zaG1f b3BfbWFwX2RtYV9idWYsCisJLnVubWFwX2RtYV9idWYgPSB0ZWVfc2htX29wX3VubWFwX2RtYV9i dWYsCisJLnJlbGVhc2UgPSB0ZWVfc2htX29wX3JlbGVhc2UsCisJLmttYXBfYXRvbWljID0gdGVl X3NobV9vcF9rbWFwX2F0b21pYywKKwkua21hcCA9IHRlZV9zaG1fb3Bfa21hcCwKKwkubW1hcCA9 IHRlZV9zaG1fb3BfbW1hcCwKK307CisKK3N0cnVjdCB0ZWVfc2htICp0ZWVfc2htX2FsbG9jKHN0 cnVjdCB0ZWVfZGV2aWNlICp0ZWVkZXYsIHNpemVfdCBzaXplLAorCQkJdTMyIGZsYWdzKQorewor CXN0cnVjdCB0ZWVfc2htX3Bvb2xfbWdyICpwb29sbSA9IE5VTEw7CisJc3RydWN0IHRlZV9zaG0g KnNobTsKKwl2b2lkICpyZXQ7CisJaW50IHJjOworCisJaWYgKCEoZmxhZ3MgJiBURUVfU0hNX01B UFBFRCkpIHsKKwkJZGV2X2Vycih0ZWVkZXYtPmRldi5wYXJlbnQsCisJCQkib25seSBtYXBwZWQg YWxsb2NhdGlvbnMgc3VwcG9ydGVkXG4iKTsKKwkJcmV0dXJuIEVSUl9QVFIoLUVJTlZBTCk7CisJ fQorCisJaWYgKChmbGFncyAmIH4oVEVFX1NITV9NQVBQRUR8VEVFX1NITV9ETUFfQlVGKSkpIHsK KwkJZGV2X2Vycih0ZWVkZXYtPmRldi5wYXJlbnQsICJpbnZhbGlkIHNobSBmbGFncyAweCV4Iiwg ZmxhZ3MpOworCQlyZXR1cm4gRVJSX1BUUigtRUlOVkFMKTsKKwl9CisKKwlpZiAoIXRlZV9kZXZp Y2VfZ2V0KHRlZWRldikpCisJCXJldHVybiBFUlJfUFRSKC1FSU5WQUwpOworCisJaWYgKCF0ZWVk ZXYtPnBvb2wpIHsKKwkJLyogdGVlZGV2IGhhcyBiZWVuIGRldGFjaGVkIGZyb20gZHJpdmVyICov CisJCXJldCA9IEVSUl9QVFIoLUVJTlZBTCk7CisJCWdvdG8gZXJyOworCX0KKworCXNobSA9IGt6 YWxsb2Moc2l6ZW9mKHN0cnVjdCB0ZWVfc2htKSwgR0ZQX0tFUk5FTCk7CisJaWYgKCFzaG0pIHsK KwkJcmV0ID0gRVJSX1BUUigtRU5PTUVNKTsKKwkJZ290byBlcnI7CisJfQorCisJc2htLT5mbGFn cyA9IGZsYWdzOworCXNobS0+dGVlZGV2ID0gdGVlZGV2OworCWlmIChmbGFncyAmIFRFRV9TSE1f RE1BX0JVRikKKwkJcG9vbG0gPSAmdGVlZGV2LT5wb29sLT5kbWFfYnVmX21ncjsKKwllbHNlCisJ CXBvb2xtID0gJnRlZWRldi0+cG9vbC0+cHJpdmF0ZV9tZ3I7CisKKwlyYyA9IHBvb2xtLT5vcHMt PmFsbG9jKHBvb2xtLCBzaG0sIHNpemUpOworCWlmIChyYykgeworCQlyZXQgPSBFUlJfUFRSKHJj KTsKKwkJZ290byBlcnI7CisJfQorCisJbXV0ZXhfbG9jaygmdGVlZGV2LT5tdXRleCk7CisJbGlz dF9hZGRfdGFpbCgmc2htLT5saXN0X25vZGUsICZ0ZWVkZXYtPmxpc3Rfc2htKTsKKwltdXRleF91 bmxvY2soJnRlZWRldi0+bXV0ZXgpOworCisJaWYgKGZsYWdzICYgVEVFX1NITV9ETUFfQlVGKSB7 CisJCURFRklORV9ETUFfQlVGX0VYUE9SVF9JTkZPKGV4cF9pbmZvKTsKKworCQlleHBfaW5mby5v cHMgPSAmdGVlX3NobV9kbWFfYnVmX29wczsKKwkJZXhwX2luZm8uc2l6ZSA9IHNobS0+c2l6ZTsK KwkJZXhwX2luZm8uZmxhZ3MgPSBPX1JEV1I7CisJCWV4cF9pbmZvLnByaXYgPSBzaG07CisKKwkJ c2htLT5kbWFidWYgPSBkbWFfYnVmX2V4cG9ydCgmZXhwX2luZm8pOworCQlpZiAoSVNfRVJSKHNo bS0+ZG1hYnVmKSkgeworCQkJcmV0ID0gRVJSX0NBU1Qoc2htLT5kbWFidWYpOworCQkJZ290byBl cnI7CisJCX0KKwl9CisKKwlyZXR1cm4gc2htOworZXJyOgorCWlmIChwb29sbSAmJiBzaG0gJiYg c2htLT5rYWRkcikKKwkJcG9vbG0tPm9wcy0+ZnJlZShwb29sbSwgc2htKTsKKwlrZnJlZShzaG0p OworCXRlZV9kZXZpY2VfcHV0KHRlZWRldik7CisJcmV0dXJuIHJldDsKK30KK0VYUE9SVF9TWU1C T0xfR1BMKHRlZV9zaG1fYWxsb2MpOworCitpbnQgdGVlX3NobV9nZXRfZmQoc3RydWN0IHRlZV9z aG0gKnNobSkKK3sKKwl1MzIgcmVxX2ZsYWdzID0gVEVFX1NITV9NQVBQRUQgfCBURUVfU0hNX0RN QV9CVUY7CisJaW50IGZkOworCisJaWYgKChzaG0tPmZsYWdzICYgcmVxX2ZsYWdzKSAhPSByZXFf ZmxhZ3MpCisJCXJldHVybiAtRUlOVkFMOworCisJZmQgPSBkbWFfYnVmX2ZkKHNobS0+ZG1hYnVm LCBPX0NMT0VYRUMpOworCWlmIChmZCA+PSAwKQorCQlnZXRfZG1hX2J1ZihzaG0tPmRtYWJ1Zik7 CisJcmV0dXJuIGZkOworfQorRVhQT1JUX1NZTUJPTF9HUEwodGVlX3NobV9nZXRfZmQpOworCitp bnQgdGVlX3NobV9wdXRfZmQoaW50IGZkKQoreworCXJldHVybiBfX2Nsb3NlX2ZkKGN1cnJlbnQt PmZpbGVzLCBmZCk7Cit9CitFWFBPUlRfU1lNQk9MX0dQTCh0ZWVfc2htX3B1dF9mZCk7CisKK3Zv aWQgdGVlX3NobV9mcmVlKHN0cnVjdCB0ZWVfc2htICpzaG0pCit7CisKKwkvKgorCSAqIGRtYV9i dWZfcHV0KCkgZGVjcmVhc2VzIHRoZSBkbWFidWYgcmVmZXJlbmNlIGNvdW50ZXIgYW5kIHdpbGwK KwkgKiBjYWxsIHRlZV9zaG1fcmVsZWFzZSgpIHdoZW4gdGhlIGxhc3QgcmVmZXJlbmNlIGlzIGdv bmUuCisJICoKKwkgKiBJbiB0aGUgY2FzZSBvZiBkcml2ZXIgcHJpdmF0ZSBtZW1vcnkgd2UgY2Fs bCB0ZWVfc2htX3JlbGVhc2UKKwkgKiBkaXJlY3RseSBpbnN0ZWFkIGFzIGl0IGRvZXNuJ3QgaGF2 ZSBhIHJlZmVyZW5jZSBjb3VudGVyLgorCSAqLworCWlmIChzaG0tPmZsYWdzICYgVEVFX1NITV9E TUFfQlVGKQorCQlkbWFfYnVmX3B1dChzaG0tPmRtYWJ1Zik7CisJZWxzZQorCQl0ZWVfc2htX3Jl bGVhc2Uoc2htKTsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKHRlZV9zaG1fZnJlZSk7CisKK3N0YXRp YyBib29sIGNtcF9rZXlfdmEoc3RydWN0IHRlZV9zaG0gKnNobSwgdWludHB0cl90IHZhKQorewor CXVpbnRwdHJfdCBzaG1fdmEgPSAodWludHB0cl90KXNobS0+a2FkZHI7CisKKwlyZXR1cm4gKHZh ID49IHNobV92YSkgJiYgKHZhIDwgKHNobV92YSArIHNobS0+c2l6ZSkpOworfQorCitzdGF0aWMg Ym9vbCBjbXBfa2V5X3BhKHN0cnVjdCB0ZWVfc2htICpzaG0sIHVpbnRwdHJfdCBwYSkKK3sKKwly ZXR1cm4gKHBhID49IHNobS0+cGFkZHIpICYmIChwYSA8IChzaG0tPnBhZGRyICsgc2htLT5zaXpl KSk7Cit9CisKK3N0YXRpYyBzdHJ1Y3QgdGVlX3NobSAqdGVlX3NobV9maW5kX2J5X2tleShzdHJ1 Y3QgdGVlX2RldmljZSAqdGVlZGV2LCB1MzIgZmxhZ3MsCisJCQlib29sICgqY21wKShzdHJ1Y3Qg dGVlX3NobSAqc2htLCB1aW50cHRyX3Qga2V5KSwKKwkJCXVpbnRwdHJfdCBrZXkpCit7CisJc3Ry dWN0IHRlZV9zaG0gKnJldCA9IE5VTEw7CisJc3RydWN0IHRlZV9zaG0gKnNobTsKKworCW11dGV4 X2xvY2soJnRlZWRldi0+bXV0ZXgpOworCWxpc3RfZm9yX2VhY2hfZW50cnkoc2htLCAmdGVlZGV2 LT5saXN0X3NobSwgbGlzdF9ub2RlKSB7CisJCWlmIChjbXAoc2htLCBrZXkpKSB7CisJCQlyZXQg PSBzaG07CisJCQlicmVhazsKKwkJfQorCX0KKwltdXRleF91bmxvY2soJnRlZWRldi0+bXV0ZXgp OworCisJcmV0dXJuIHJldDsKK30KKworc3RydWN0IHRlZV9zaG0gKnRlZV9zaG1fZmluZF9ieV92 YShzdHJ1Y3QgdGVlX2RldmljZSAqdGVlZGV2LCB1MzIgZmxhZ3MsCisJCQl2b2lkICp2YSkKK3sK KwlyZXR1cm4gdGVlX3NobV9maW5kX2J5X2tleSh0ZWVkZXYsIGZsYWdzLCBjbXBfa2V5X3ZhLCAo dWludHB0cl90KXZhKTsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKHRlZV9zaG1fZmluZF9ieV92YSk7 CisKK3N0cnVjdCB0ZWVfc2htICp0ZWVfc2htX2ZpbmRfYnlfcGEoc3RydWN0IHRlZV9kZXZpY2Ug KnRlZWRldiwgdTMyIGZsYWdzLAorCQkJcGh5c19hZGRyX3QgcGEpCit7CisJcmV0dXJuIHRlZV9z aG1fZmluZF9ieV9rZXkodGVlZGV2LCBmbGFncywgY21wX2tleV9wYSwgcGEpOworfQorRVhQT1JU X1NZTUJPTF9HUEwodGVlX3NobV9maW5kX2J5X3BhKTsKKworaW50IHRlZV9zaG1fdmEycGEoc3Ry dWN0IHRlZV9zaG0gKnNobSwgdm9pZCAqdmEsIHBoeXNfYWRkcl90ICpwYSkKK3sKKwkvKiBDaGVj ayB0aGF0IHdlJ3JlIGluIHRoZSByYW5nZSBvZiB0aGUgc2htICovCisJaWYgKChjaGFyICopdmEg PCAoY2hhciAqKXNobS0+a2FkZHIpCisJCXJldHVybiAtRUlOVkFMOworCWlmICgoY2hhciAqKXZh ID49ICgoY2hhciAqKXNobS0+a2FkZHIgKyBzaG0tPnNpemUpKQorCQlyZXR1cm4gLUVJTlZBTDsK KworCXJldHVybiB0ZWVfc2htX2dldF9wYSgKKwkJCXNobSwgKHVuc2lnbmVkIGxvbmcpdmEgLSAo dW5zaWduZWQgbG9uZylzaG0tPmthZGRyLCBwYSk7Cit9CitFWFBPUlRfU1lNQk9MX0dQTCh0ZWVf c2htX3ZhMnBhKTsKKworaW50IHRlZV9zaG1fcGEydmEoc3RydWN0IHRlZV9zaG0gKnNobSwgcGh5 c19hZGRyX3QgcGEsIHZvaWQgKip2YSkKK3sKKwkvKiBDaGVjayB0aGF0IHdlJ3JlIGluIHRoZSBy YW5nZSBvZiB0aGUgc2htICovCisJaWYgKHBhIDwgc2htLT5wYWRkcikKKwkJcmV0dXJuIC1FSU5W QUw7CisJaWYgKHBhID49IChzaG0tPnBhZGRyICsgc2htLT5zaXplKSkKKwkJcmV0dXJuIC1FSU5W QUw7CisKKwlpZiAodmEpIHsKKwkJdm9pZCAqdiA9IHRlZV9zaG1fZ2V0X3ZhKHNobSwgcGEgLSBz aG0tPnBhZGRyKTsKKworCQlpZiAoSVNfRVJSKHYpKQorCQkJcmV0dXJuIFBUUl9FUlIodik7CisJ CSp2YSA9IHY7CisJfQorCXJldHVybiAwOworfQorRVhQT1JUX1NZTUJPTF9HUEwodGVlX3NobV9w YTJ2YSk7CisKK3ZvaWQgKnRlZV9zaG1fZ2V0X3ZhKHN0cnVjdCB0ZWVfc2htICpzaG0sIHNpemVf dCBvZmZzKQoreworCWlmIChvZmZzID49IHNobS0+c2l6ZSkKKwkJcmV0dXJuIEVSUl9QVFIoLUVJ TlZBTCk7CisJcmV0dXJuIChjaGFyICopc2htLT5rYWRkciArIG9mZnM7Cit9CitFWFBPUlRfU1lN Qk9MX0dQTCh0ZWVfc2htX2dldF92YSk7CisKK2ludCB0ZWVfc2htX2dldF9wYShzdHJ1Y3QgdGVl X3NobSAqc2htLCBzaXplX3Qgb2ZmcywgcGh5c19hZGRyX3QgKnBhKQoreworCWlmIChvZmZzID49 IHNobS0+c2l6ZSkKKwkJcmV0dXJuIC1FSU5WQUw7CisJaWYgKHBhKQorCQkqcGEgPSBzaG0tPnBh ZGRyICsgb2ZmczsKKwlyZXR1cm4gMDsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKHRlZV9zaG1fZ2V0 X3BhKTsKKworc3RhdGljIGJvb2wgaXNfc2htX2RtYV9idWYoc3RydWN0IGRtYV9idWYgKmRtYWJ1 ZikKK3sKKwlyZXR1cm4gZG1hYnVmLT5vcHMgPT0gJnRlZV9zaG1fZG1hX2J1Zl9vcHM7Cit9CisK K3N0cnVjdCB0ZWVfc2htICp0ZWVfc2htX2dldF9mcm9tX2ZkKGludCBmZCkKK3sKKwlzdHJ1Y3Qg ZG1hX2J1ZiAqZG1hYnVmID0gZG1hX2J1Zl9nZXQoZmQpOworCisJaWYgKElTX0VSUihkbWFidWYp KQorCQlyZXR1cm4gRVJSX0NBU1QoZG1hYnVmKTsKKworCWlmICghaXNfc2htX2RtYV9idWYoZG1h YnVmKSkgeworCQlkbWFfYnVmX3B1dChkbWFidWYpOworCQlyZXR1cm4gRVJSX1BUUigtRUlOVkFM KTsKKwl9CisJcmV0dXJuIGRtYWJ1Zi0+cHJpdjsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKHRlZV9z aG1fZ2V0X2Zyb21fZmQpOworCit2b2lkIHRlZV9zaG1fcHV0KHN0cnVjdCB0ZWVfc2htICpzaG0p Cit7CisJaWYgKHNobS0+ZmxhZ3MgJiBURUVfU0hNX0RNQV9CVUYpCisJCWRtYV9idWZfcHV0KHNo bS0+ZG1hYnVmKTsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKHRlZV9zaG1fcHV0KTsKZGlmZiAtLWdp dCBhL2RyaXZlcnMvdGVlL3RlZV9zaG1fcG9vbC5jIGIvZHJpdmVycy90ZWUvdGVlX3NobV9wb29s LmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uMmVmMjJiYwotLS0gL2Rldi9u dWxsCisrKyBiL2RyaXZlcnMvdGVlL3RlZV9zaG1fcG9vbC5jCkBAIC0wLDAgKzEsMTMzIEBACisv KgorICogQ29weXJpZ2h0IChjKSAyMDE1LCBMaW5hcm8gTGltaXRlZAorICoKKyAqIFRoaXMgc29m dHdhcmUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJs aWMKKyAqIExpY2Vuc2UgdmVyc2lvbiAyLCBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdh cmUgRm91bmRhdGlvbiwgYW5kCisgKiBtYXkgYmUgY29waWVkLCBkaXN0cmlidXRlZCwgYW5kIG1v ZGlmaWVkIHVuZGVyIHRob3NlIHRlcm1zLgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmli dXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLAorICogYnV0IFdJVEhPVVQg QU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YKKyAqIE1F UkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0 aGUKKyAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCisgKgor ICovCisjaW5jbHVkZSA8bGludXgvZGV2aWNlLmg+CisjaW5jbHVkZSA8bGludXgvZG1hLWJ1Zi5o PgorI2luY2x1ZGUgPGxpbnV4L3NsYWIuaD4KKyNpbmNsdWRlIDxsaW51eC9nZW5hbGxvYy5oPgor I2luY2x1ZGUgPGxpbnV4L3RlZV9kcnYuaD4KKyNpbmNsdWRlICJ0ZWVfcHJpdmF0ZS5oIgorCitz dGF0aWMgaW50IHBvb2xfb3BfZ2VuX2FsbG9jKHN0cnVjdCB0ZWVfc2htX3Bvb2xfbWdyICpwb29s bSwKKwkJCXN0cnVjdCB0ZWVfc2htICpzaG0sIHNpemVfdCBzaXplKQoreworCXVuc2lnbmVkIGxv bmcgdmE7CisJc3RydWN0IGdlbl9wb29sICpnZW5wb29sID0gcG9vbG0tPnByaXZhdGVfZGF0YTsK KwlzaXplX3QgcyA9IHJvdW5kdXAoc2l6ZSwgMSA8PCBnZW5wb29sLT5taW5fYWxsb2Nfb3JkZXIp OworCisJdmEgPSBnZW5fcG9vbF9hbGxvYyhnZW5wb29sLCBzKTsKKwlpZiAoIXZhKQorCQlyZXR1 cm4gLUVOT01FTTsKKwlzaG0tPmthZGRyID0gKHZvaWQgKil2YTsKKwlzaG0tPnBhZGRyID0gZ2Vu X3Bvb2xfdmlydF90b19waHlzKGdlbnBvb2wsIHZhKTsKKwlzaG0tPnNpemUgPSBzOworCXJldHVy biAwOworfQorCitzdGF0aWMgdm9pZCBwb29sX29wX2dlbl9mcmVlKHN0cnVjdCB0ZWVfc2htX3Bv b2xfbWdyICpwb29sbSwKKwkJCXN0cnVjdCB0ZWVfc2htICpzaG0pCit7CisJZ2VuX3Bvb2xfZnJl ZShwb29sbS0+cHJpdmF0ZV9kYXRhLCAodW5zaWduZWQgbG9uZylzaG0tPmthZGRyLAorCQkgICAg ICBzaG0tPnNpemUpOworCXNobS0+a2FkZHIgPSBOVUxMOworfQorCitzdGF0aWMgY29uc3Qgc3Ry dWN0IHRlZV9zaG1fcG9vbF9tZ3Jfb3BzIHBvb2xfb3BzX2dlbmVyaWMgPSB7CisJLmFsbG9jID0g cG9vbF9vcF9nZW5fYWxsb2MsCisJLmZyZWUgPSBwb29sX29wX2dlbl9mcmVlLAorfTsKKworc3Rh dGljIHZvaWQgcG9vbF9yZXNfbWVtX2Rlc3Ryb3koc3RydWN0IHRlZV9zaG1fcG9vbCAqcG9vbCkK K3sKKwlnZW5fcG9vbF9kZXN0cm95KHBvb2wtPnByaXZhdGVfbWdyLnByaXZhdGVfZGF0YSk7CisJ Z2VuX3Bvb2xfZGVzdHJveShwb29sLT5kbWFfYnVmX21nci5wcml2YXRlX2RhdGEpOworfQorCitz dGF0aWMgaW50IHBvb2xfcmVzX21lbV9tZ3JfaW5pdChzdHJ1Y3QgdGVlX3NobV9wb29sX21nciAq bWdyLAorCQkJc3RydWN0IHRlZV9zaG1fcG9vbF9tZW1faW5mbyAqaW5mbywgaW50IG1pbl9hbGxv Y19vcmRlcikKK3sKKwlzaXplX3QgcGFnZV9tYXNrID0gUEFHRV9TSVpFIC0gMTsKKwlzdHJ1Y3Qg Z2VuX3Bvb2wgKmdlbnBvb2wgPSBOVUxMOworCWludCByYzsKKworCS8qCisJICogU3RhcnQgYW5k IGVuZCBtdXN0IGJlIHBhZ2UgYWxpZ25lZAorCSAqLworCWlmICgoaW5mby0+dmFkZHIgJiBwYWdl X21hc2spIHx8IChpbmZvLT5wYWRkciAmIHBhZ2VfbWFzaykgfHwKKwkgICAgKGluZm8tPnNpemUg JiBwYWdlX21hc2spKQorCQlyZXR1cm4gLUVJTlZBTDsKKworCWdlbnBvb2wgPSBnZW5fcG9vbF9j cmVhdGUobWluX2FsbG9jX29yZGVyLCAtMSk7CisJaWYgKCFnZW5wb29sKQorCQlyZXR1cm4gLUVO T01FTTsKKworCWdlbl9wb29sX3NldF9hbGdvKGdlbnBvb2wsIGdlbl9wb29sX2Jlc3RfZml0LCBO VUxMKTsKKwlyYyA9IGdlbl9wb29sX2FkZF92aXJ0KGdlbnBvb2wsIGluZm8tPnZhZGRyLCBpbmZv LT5wYWRkciwgaW5mby0+c2l6ZSwKKwkJCSAgICAgICAtMSk7CisJaWYgKHJjKSB7CisJCWdlbl9w b29sX2Rlc3Ryb3koZ2VucG9vbCk7CisJCXJldHVybiByYzsKKwl9CisKKwltZ3ItPnByaXZhdGVf ZGF0YSA9IGdlbnBvb2w7CisJbWdyLT5vcHMgPSAmcG9vbF9vcHNfZ2VuZXJpYzsKKwlyZXR1cm4g MDsKK30KKworc3RydWN0IHRlZV9zaG1fcG9vbCAqdGVlX3NobV9wb29sX2FsbG9jX3Jlc19tZW0o c3RydWN0IGRldmljZSAqZGV2LAorCQkJc3RydWN0IHRlZV9zaG1fcG9vbF9tZW1faW5mbyAqcHJp dl9pbmZvLAorCQkJc3RydWN0IHRlZV9zaG1fcG9vbF9tZW1faW5mbyAqZG1hYnVmX2luZm8pCit7 CisJc3RydWN0IHRlZV9zaG1fcG9vbCAqcG9vbCA9IE5VTEw7CisJaW50IHJldDsKKworCXBvb2wg PSBremFsbG9jKHNpemVvZigqcG9vbCksIEdGUF9LRVJORUwpOworCWlmICghcG9vbCkgeworCQly ZXQgPSAtRU5PTUVNOworCQlnb3RvIGVycjsKKwl9CisKKwkvKgorCSAqIENyZWF0ZSB0aGUgcG9v bCBmb3IgZHJpdmVyIHByaXZhdGUgc2hhcmVkIG1lbW9yeQorCSAqLworCXJldCA9IHBvb2xfcmVz X21lbV9tZ3JfaW5pdCgmcG9vbC0+cHJpdmF0ZV9tZ3IsIHByaXZfaW5mbywKKwkJCQkgICAgMyAv KiA4IGJ5dGUgYWxpZ25lZCAqLyk7CisJaWYgKHJldCkKKwkJZ290byBlcnI7CisKKwkvKgorCSAq IENyZWF0ZSB0aGUgcG9vbCBmb3IgZG1hX2J1ZiBzaGFyZWQgbWVtb3J5CisJICovCisJcmV0ID0g cG9vbF9yZXNfbWVtX21ncl9pbml0KCZwb29sLT5kbWFfYnVmX21nciwgZG1hYnVmX2luZm8sCisJ CQkJICAgIFBBR0VfU0hJRlQpOworCWlmIChyZXQpCisJCWdvdG8gZXJyOworCisJcG9vbC0+ZGVz dHJveSA9IHBvb2xfcmVzX21lbV9kZXN0cm95OworCXJldHVybiBwb29sOworZXJyOgorCWlmIChy ZXQgPT0gLUVOT01FTSkKKwkJZGV2X2VycihkZXYsICJjYW4ndCBhbGxvY2F0ZSBtZW1vcnkgZm9y IHJlc19tZW0gc2hhcmVkIG1lbW9yeSBwb29sXG4iKTsKKwlpZiAocG9vbCAmJiBwb29sLT5wcml2 YXRlX21nci5wcml2YXRlX2RhdGEpCisJCWdlbl9wb29sX2Rlc3Ryb3kocG9vbC0+cHJpdmF0ZV9t Z3IucHJpdmF0ZV9kYXRhKTsKKwlrZnJlZShwb29sKTsKKwlyZXR1cm4gRVJSX1BUUihyZXQpOwor fQorRVhQT1JUX1NZTUJPTF9HUEwodGVlX3NobV9wb29sX2FsbG9jX3Jlc19tZW0pOworCit2b2lk IHRlZV9zaG1fcG9vbF9mcmVlKHN0cnVjdCB0ZWVfc2htX3Bvb2wgKnBvb2wpCit7CisJcG9vbC0+ ZGVzdHJveShwb29sKTsKKwlrZnJlZShwb29sKTsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKHRlZV9z aG1fcG9vbF9mcmVlKTsKZGlmZiAtLWdpdCBhL2luY2x1ZGUvbGludXgvdGVlX2Rydi5oIGIvaW5j bHVkZS9saW51eC90ZWVfZHJ2LmgKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4u MDZjZmZhNgotLS0gL2Rldi9udWxsCisrKyBiL2luY2x1ZGUvbGludXgvdGVlX2Rydi5oCkBAIC0w LDAgKzEsMjk5IEBACisvKgorICogQ29weXJpZ2h0IChjKSAyMDE1LCBMaW5hcm8gTGltaXRlZAor ICoKKyAqIFRoaXMgc29mdHdhcmUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBH TlUgR2VuZXJhbCBQdWJsaWMKKyAqIExpY2Vuc2UgdmVyc2lvbiAyLCBhcyBwdWJsaXNoZWQgYnkg dGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgYW5kCisgKiBtYXkgYmUgY29waWVkLCBkaXN0 cmlidXRlZCwgYW5kIG1vZGlmaWVkIHVuZGVyIHRob3NlIHRlcm1zLgorICoKKyAqIFRoaXMgcHJv Z3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLAor ICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2Fy cmFudHkgb2YKKyAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIg UFVSUE9TRS4gIFNlZSB0aGUKKyAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3Jl IGRldGFpbHMuCisgKgorICovCisKKyNpZm5kZWYgX19URUVfRFJWX0gKKyNkZWZpbmUgX19URUVf RFJWX0gKKworI2luY2x1ZGUgPGxpbnV4L3R5cGVzLmg+CisjaW5jbHVkZSA8bGludXgvbGlzdC5o PgorI2luY2x1ZGUgPGxpbnV4L3RlZS5oPgorCisvKgorICogVGhlIGZpbGUgZGVzY3JpYmVzIHRo ZSBBUEkgcHJvdmlkZWQgYnkgdGhlIGdlbmVyaWMgVEVFIGRyaXZlciB0byB0aGUKKyAqIHNwZWNp ZmljIFRFRSBkcml2ZXIuCisgKi8KKworI2RlZmluZSBURUVfU0hNX01BUFBFRAkJMHgxCS8qIE1l bW9yeSBtYXBwZWQgYnkgdGhlIGtlcm5lbCAqLworI2RlZmluZSBURUVfU0hNX0RNQV9CVUYJCTB4 MgkvKiBNZW1vcnkgd2l0aCBkbWEtYnVmIGhhbmRsZSAqLworCitzdHJ1Y3QgdGVlX2RldmljZTsK K3N0cnVjdCB0ZWVfc2htOworc3RydWN0IHRlZV9zaG1fcG9vbDsKKworLyoqCisgKiBzdHJ1Y3Qg dGVlX2NvbnRleHQgLSBkcml2ZXIgc3BlY2lmaWMgY29udGV4dCBvbiBmaWxlIHBvaW50ZXIgZGF0 YQorICogQHRlZWRldjoJcG9pbnRlciB0byB0aGlzIGRyaXZlcnMgc3RydWN0IHRlZV9kZXZpY2UK KyAqIEBkYXRhOglkcml2ZXIgc3BlY2lmaWMgY29udGV4dCBkYXRhLCBtYW5hZ2VkIGJ5IHRoZSBk cml2ZXIKKyAqLworc3RydWN0IHRlZV9jb250ZXh0IHsKKwlzdHJ1Y3QgdGVlX2RldmljZSAqdGVl ZGV2OworCXZvaWQgKmRhdGE7Cit9OworCitzdHJ1Y3QgdGVlX3BhcmFtX21lbXJlZiB7CisJc2l6 ZV90IHNobV9vZmZzOworCXNpemVfdCBzaXplOworCXN0cnVjdCB0ZWVfc2htICpzaG07Cit9Owor CitzdHJ1Y3QgdGVlX3BhcmFtX3ZhbHVlIHsKKwl1NjQgYTsKKwl1NjQgYjsKKwl1NjQgYzsKK307 CisKK3N0cnVjdCB0ZWVfcGFyYW0geworCXU2NCBhdHRyOworCXVuaW9uIHsKKwkJc3RydWN0IHRl ZV9wYXJhbV9tZW1yZWYgbWVtcmVmOworCQlzdHJ1Y3QgdGVlX3BhcmFtX3ZhbHVlIHZhbHVlOwor CX0gdTsKK307CisKKy8qKgorICogc3RydWN0IHRlZV9kcml2ZXJfb3BzIC0gZHJpdmVyIG9wZXJh dGlvbnMgdnRhYmxlCisgKiBAZ2V0X3ZlcnNpb246CXJldHVybnMgdmVyc2lvbiBvZiBkcml2ZXIK KyAqIEBvcGVuOgkJY2FsbGVkIHdoZW4gdGhlIGRldmljZSBmaWxlIGlzIG9wZW5lZAorICogQHJl bGVhc2U6CQlyZWxlYXNlIHRoaXMgb3BlbiBmaWxlCisgKi8KK3N0cnVjdCB0ZWVfZHJpdmVyX29w cyB7CisJdm9pZCAoKmdldF92ZXJzaW9uKShzdHJ1Y3QgdGVlX2RldmljZSAqdGVlZGV2LAorCQkJ c3RydWN0IHRlZV9pb2N0bF92ZXJzaW9uX2RhdGEgKnZlcnMpOworCWludCAoKm9wZW4pKHN0cnVj dCB0ZWVfY29udGV4dCAqY3R4KTsKKwl2b2lkICgqcmVsZWFzZSkoc3RydWN0IHRlZV9jb250ZXh0 ICpjdHgpOworCWludCAoKm9wZW5fc2Vzc2lvbikoc3RydWN0IHRlZV9jb250ZXh0ICpjdHgsCisJ CQlzdHJ1Y3QgdGVlX2lvY3RsX29wZW5fc2Vzc2lvbl9hcmcgKmFyZywKKwkJCXN0cnVjdCB0ZWVf cGFyYW0gKnBhcmFtKTsKKwlpbnQgKCpjbG9zZV9zZXNzaW9uKShzdHJ1Y3QgdGVlX2NvbnRleHQg KmN0eCwgdTMyIHNlc3Npb24pOworCWludCAoKmludm9rZV9mdW5jKShzdHJ1Y3QgdGVlX2NvbnRl eHQgKmN0eCwKKwkJCXN0cnVjdCB0ZWVfaW9jdGxfaW52b2tlX2FyZyAqYXJnLAorCQkJc3RydWN0 IHRlZV9wYXJhbSAqcGFyYW0pOworCWludCAoKmNhbmNlbF9yZXEpKHN0cnVjdCB0ZWVfY29udGV4 dCAqY3R4LCB1MzIgY2FuY2VsX2lkLCB1MzIgc2Vzc2lvbik7CisJaW50ICgqc3VwcF9yZWN2KShz dHJ1Y3QgdGVlX2NvbnRleHQgKmN0eCwgdTMyICpmdW5jLCB1MzIgKm51bV9wYXJhbXMsCisJCQlz dHJ1Y3QgdGVlX3BhcmFtICpwYXJhbSk7CisJaW50ICgqc3VwcF9zZW5kKShzdHJ1Y3QgdGVlX2Nv bnRleHQgKmN0eCwgdTMyIHJldCwgdTMyIG51bV9wYXJhbXMsCisJCQlzdHJ1Y3QgdGVlX3BhcmFt ICpwYXJhbSk7Cit9OworCisvKioKKyAqIHN0cnVjdCB0ZWVfZGVzYyAtIERlc2NyaWJlcyB0aGUg VEVFIGRyaXZlciB0byB0aGUgc3Vic3lzdGVtCisgKiBAbmFtZToJbmFtZSBvZiBkcml2ZXIKKyAq IEBvcHM6CWRyaXZlciBvcGVyYXRpb25zIHZ0YWJsZQorICogQG93bmVyOgltb2R1bGUgcHJvdmlk aW5nIHRoZSBkcml2ZXIKKyAqIEBmbGFnczoJRXh0cmEgcHJvcGVydGllcyBvZiBkcml2ZXIsIGRl ZmluZWQgYnkgVEVFX0RFU0NfKiBiZWxvdworICovCisjZGVmaW5lIFRFRV9ERVNDX1BSSVZJTEVH RUQJMHgxCitzdHJ1Y3QgdGVlX2Rlc2MgeworCWNvbnN0IGNoYXIgKm5hbWU7CisJY29uc3Qgc3Ry dWN0IHRlZV9kcml2ZXJfb3BzICpvcHM7CisJc3RydWN0IG1vZHVsZSAqb3duZXI7CisJdTMyIGZs YWdzOworfTsKKworCisvKioKKyAqIHRlZV9kZXZpY2VfYWxsb2MoKSAtIEFsbG9jYXRlIGEgbmV3 IHN0cnVjdCB0ZWVfZGV2aWNlIGluc3RhbmNlCisgKiBAdGVlZGVzYzoJRGVzY3JpcHRvciBmb3Ig dGhpcyBkcml2ZXIKKyAqIEBkZXY6CVBhcmVudCBkZXZpY2UgZm9yIHRoaXMgZGV2aWNlCisgKiBA cG9vbDoJU2hhcmVkIG1lbW9yeSBwb29sLCBOVUxMIGlmIG5vdCB1c2VkCisgKiBAZHJpdmVyX2Rh dGE6IFByaXZhdGUgZHJpdmVyIGRhdGEgZm9yIHRoaXMgZGV2aWNlCisgKgorICogQWxsb2NhdGVz IGEgbmV3IHN0cnVjdCB0ZWVfZGV2aWNlIGluc3RhbmNlLiBUaGUgZGV2aWNlIGlzCisgKiByZW1v dmVkIGJ5IHRlZV9kZXZpY2VfdW5yZWdpc3RlcigpLgorICoKKyAqIEByZXR1cm5zIGEgcG9pbnRl ciB0byBhICdzdHJ1Y3QgdGVlX2RldmljZScgb3IgYW4gRVJSX1BUUiBvbiBmYWlsdXJlCisgKi8K K3N0cnVjdCB0ZWVfZGV2aWNlICp0ZWVfZGV2aWNlX2FsbG9jKGNvbnN0IHN0cnVjdCB0ZWVfZGVz YyAqdGVlZGVzYywKKwkJCXN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0IHRlZV9zaG1fcG9vbCAq cG9vbCwKKwkJCXZvaWQgKmRyaXZlcl9kYXRhKTsKKworLyoqCisgKiB0ZWVfZGV2aWNlX3JlZ2lz dGVyKCkgLSBSZWdpc3RlcnMgYSBURUUgZGV2aWNlCisgKiBAdGVlZGV2OglEZXZpY2UgdG8gcmVn aXN0ZXIKKyAqCisgKiB0ZWVfZGV2aWNlX3VucmVnaXN0ZXIoKSBuZWVkIHRvIGJlIGNhbGxlZCB0 byByZW1vdmUgdGhlIEB0ZWVkZXYgaWYKKyAqIHRoaXMgZnVuY3Rpb24gZmFpbHMuCisgKgorICog QHJldHVybnMgPCAwIG9uIGZhaWx1cmUKKyAqLworaW50IHRlZV9kZXZpY2VfcmVnaXN0ZXIoc3Ry dWN0IHRlZV9kZXZpY2UgKnRlZWRldik7CisKKy8qKgorICogdGVlX2RldmljZV91bnJlZ2lzdGVy KCkgLSBSZW1vdmVzIGEgVEVFIGRldmljZQorICogQHRlZWRldjoJRGV2aWNlIHRvIHVucmVnaXN0 ZXIKKyAqCisgKiBUaGlzIGZ1bmN0aW9uIHNob3VsZCBiZSBjYWxsZWQgdG8gcmVtb3ZlIHRoZSBA dGVlZGV2IGV2ZW4gaWYKKyAqIHRlZV9kZXZpY2VfcmVnaXN0ZXIoKSBoYXNuJ3QgYmVlbiBjYWxs ZWQgeWV0LiBEb2VzIG5vdGhpbmcgaWYKKyAqIEB0ZWVkZXYgaXMgTlVMTC4KKyAqLwordm9pZCB0 ZWVfZGV2aWNlX3VucmVnaXN0ZXIoc3RydWN0IHRlZV9kZXZpY2UgKnRlZWRldik7CisKKy8qKgor ICogc3RydWN0IHRlZV9zaG1fcG9vbF9tZW1faW5mbyAtIGhvbGRzIGluZm9ybWF0aW9uIG5lZWRl ZCB0byBjcmVhdGUgYSBzaGFyZWQgbWVtb3J5IHBvb2wKKyAqIEB2YWRkcjoJVmlydHVhbCBhZGRy ZXNzIG9mIHN0YXJ0IG9mIHBvb2wKKyAqIEBwYWRkcjoJUGh5c2ljYWwgYWRkcmVzcyBvZiBzdGFy dCBvZiBwb29sCisgKiBAc2l6ZToJU2l6ZSBpbiBieXRlcyBvZiB0aGUgcG9vbAorICovCitzdHJ1 Y3QgdGVlX3NobV9wb29sX21lbV9pbmZvIHsKKwl1bnNpZ25lZCBsb25nIHZhZGRyOworCXVuc2ln bmVkIGxvbmcgcGFkZHI7CisJc2l6ZV90IHNpemU7Cit9OworCisvKioKKyAqIHRlZV9zaG1fcG9v bF9hbGxvY19yZXNfbWVtKCkgLSBDcmVhdGUgYSBzaGFyZWQgbWVtb3J5IHBvb2wgZnJvbSByZXNl cnZlZCBtZW1vcnkgcmFuZ2UKKyAqIEBkZXY6CURldmljZSBhbGxvY2F0aW5nIHRoZSBwb29sCisg KiBAcHJpdl9pbmZvOglJbmZvcm1hdGlvbiBmb3IgZHJpdmVyIHByaXZhdGUgc2hhcmVkIG1lbW9y eSBwb29sCisgKiBAZG1hYnVmX2luZm86IEluZm9ybWF0aW9uIGZvciBkbWEtYnVmIHNoYXJlZCBt ZW1vcnkgcG9vbAorICoKKyAqIFN0YXJ0IGFuZCBlbmQgb2YgcG9vbHMgd2lsbCBtdXN0IGJlIHBh Z2UgYWxpZ25lZC4KKyAqCisgKiBBbGxvY2F0aW9uIHdpdGggdGhlIGZsYWcgVEVFX1NITV9ETUFf QlVGIHNldCB3aWxsIHVzZSB0aGUgcmFuZ2Ugc3VwcGxpZWQKKyAqIGluIEBkbWFidWYsIG90aGVy cyB3aWxsIHVzZSB0aGUgcmFuZ2UgcHJvdmlkZWQgYnkgQHByaXYuCisgKgorICogQHJldHVybnMg cG9pbnRlciB0byBhICdzdHJ1Y3QgdGVlX3NobV9wb29sJyBvciBhbiBFUlJfUFRSIG9uIGZhaWx1 cmUuCisgKi8KK3N0cnVjdCB0ZWVfc2htX3Bvb2wgKnRlZV9zaG1fcG9vbF9hbGxvY19yZXNfbWVt KHN0cnVjdCBkZXZpY2UgKmRldiwKKwkJCXN0cnVjdCB0ZWVfc2htX3Bvb2xfbWVtX2luZm8gKnBy aXZfaW5mbywKKwkJCXN0cnVjdCB0ZWVfc2htX3Bvb2xfbWVtX2luZm8gKmRtYWJ1Zl9pbmZvKTsK KworLyoqCisgKiB0ZWVfc2htX3Bvb2xfZnJlZSgpIC0gRnJlZSBhIHNoYXJlZCBtZW1vcnkgcG9v bAorICogQHBvb2w6CVRoZSBzaGFyZWQgbWVtb3J5IHBvb2wgdG8gZnJlZQorICoKKyAqIFRoZSBt dXN0IGJlIG5vIHJlbWFpbmluZyBzaGFyZWQgbWVtb3J5IGFsbG9jYXRlZCBmcm9tIHRoaXMgcG9v bCB3aGVuCisgKiB0aGlzIGZ1bmN0aW9uIGlzIGNhbGxlZC4KKyAqLwordm9pZCB0ZWVfc2htX3Bv b2xfZnJlZShzdHJ1Y3QgdGVlX3NobV9wb29sICpwb29sKTsKKworLyoqCisgKiB0ZWVfZ2V0X2Ry dmRhdGEoKSAtIFJldHVybiBkcml2ZXJfZGF0YSBwb2ludGVyCisgKiBAcmV0dXJucyB0aGUgZHJp dmVyX2RhdGEgcG9pbnRlciBzdXBwbGllZCB0byB0ZWVfcmVnaXN0ZXIoKS4KKyAqLwordm9pZCAq dGVlX2dldF9kcnZkYXRhKHN0cnVjdCB0ZWVfZGV2aWNlICp0ZWVkZXYpOworCisvKioKKyAqIHRl ZV9zaG1fYWxsb2MoKSAtIEFsbG9jYXRlIHNoYXJlZCBtZW1vcnkKKyAqIEB0ZWVkZXY6CURyaXZl ciB0aGF0IGFsbG9jYXRlcyB0aGUgc2hhcmVkIG1lbW9yeQorICogQHNpemU6CVJlcXVlc3RlZCBz aXplIG9mIHNoYXJlZCBtZW1vcnkKKyAqIEBmbGFnczoJRmxhZ3Mgc2V0dGluZyBwcm9wZXJ0aWVz IGZvciB0aGUgcmVxdWVzdGVkIHNoYXJlZCBtZW1vcnkuCisgKgorICogTWVtb3J5IGFsbG9jYXRl ZCBhcyBnbG9iYWwgc2hhcmVkIG1lbW9yeSBpcyBhdXRvbWF0aWNhbGx5IGZyZWVkIHdoZW4gdGhl CisgKiBURUUgZmlsZSBwb2ludGVyIGlzIGNsb3NlZC4gVGhlIEBmbGFncyBmaWVsZCB1c2VzIHRo ZSBiaXRzIGRlZmluZWQgYnkKKyAqIFRFRV9TSE1fKiBhYm92ZS4gVEVFX1NITV9NQVBQRUQgbXVz dCBjdXJyZW50bHkgYWx3YXlzIGJlIHNldC4gSWYKKyAqIFRFRV9TSE1fRE1BX0JVRiBnbG9iYWwg c2hhcmVkIG1lbW9yeSB3aWxsIGJlIGFsbG9jYXRlZCBhbmQgYXNzb2NpYXRlZAorICogd2l0aCBh IGRtYS1idWYgaGFuZGxlLCBlbHNlIGRyaXZlciBwcml2YXRlIG1lbW9yeS4KKyAqCisgKiBAcmV0 dXJucyBhIHBvaW50ZXIgdG8gJ3N0cnVjdCB0ZWVfc2htJworICovCitzdHJ1Y3QgdGVlX3NobSAq dGVlX3NobV9hbGxvYyhzdHJ1Y3QgdGVlX2RldmljZSAqdGVlZGV2LCBzaXplX3Qgc2l6ZSwKKwkJ CXUzMiBmbGFncyk7CisKKy8qKgorICogdGVlX3NobV9mcmVlKCkgLSBGcmVlIHNoYXJlZCBtZW1v cnkKKyAqIEBzaG06CUhhbmRsZSB0byBzaGFyZWQgbWVtb3J5IHRvIGZyZWUKKyAqLwordm9pZCB0 ZWVfc2htX2ZyZWUoc3RydWN0IHRlZV9zaG0gKnNobSk7CisKKy8qKgorICogdGVlX3NobV9maW5k X2J5X3ZhKCkgLSBGaW5kIGEgc2hhcmVkIG1lbW9yeSBoYW5kbGUgYnkgYSB2aXJ0dWFsIGFkZHJl c3MKKyAqIEB0ZWVkZXY6CVRoZSBkZXZpY2UgdGhhdCBvd25zIHRoZSBzaGFyZWQgbWVtb3J5Cisg KiBAZmxhZ3M6CVNlbGVjdCB3aGljaCB0eXBlIG9mIHNoYXJlZCBtZW1vcnkgdG8gbG9jYXRlLCBp ZgorICoJCVRFRV9TSE1fRE1BX0JVRiBnbG9iYWwgc2hhcmVkIG1lbW9yeSBlbHNlIGRyaXZlciBw cml2YXRlCisgKgkJc2hhcmVkIG1lbW9yeS4KKyAqIEB2YToJCVZpcnR1YWwgYWRkcmVzcyBjb3Zl cmVkIGJ5IHRoZSBzaGFyZWQgbWVtb3J5CisgKiBAcmV0dXJucyBhIEhhbmRsZSB0byBzaGFyZWQg bWVtb3J5CisgKi8KK3N0cnVjdCB0ZWVfc2htICp0ZWVfc2htX2ZpbmRfYnlfdmEoc3RydWN0IHRl ZV9kZXZpY2UgKnRlZWRldiwgdTMyIGZsYWdzLAorCQkJdm9pZCAqdmEpOworLyoqCisgKiB0ZWVf c2htX2ZpbmRfYnlfcGEoKSAtIEZpbmQgYSBzaGFyZWQgbWVtb3J5IGhhbmRsZSBieSBhIHBoeXNp Y2FsIGFkZHJlc3MKKyAqIEB0ZWVkZXY6CVRoZSBkZXZpY2UgdGhhdCBvd25zIHRoZSBzaGFyZWQg bWVtb3J5CisgKiBAZmxhZ3M6CVNlbGVjdCB3aGljaCB0eXBlIG9mIHNoYXJlZCBtZW1vcnkgdG8g bG9jYXRlLCBpZgorICoJCVRFRV9TSE1fRE1BX0JVRiBnbG9iYWwgc2hhcmVkIG1lbW9yeSBlbHNl IGRyaXZlciBwcml2YXRlCisgKgkJc2hhcmVkIG1lbW9yeS4KKyAqIEBwYToJCVBoeXNpY2FsIGFk ZHJlc3MgY292ZXJlZCBieSB0aGUgc2hhcmVkIG1lbW9yeQorICogQHJldHVybnMgYSBIYW5kbGUg dG8gc2hhcmVkIG1lbW9yeQorICovCitzdHJ1Y3QgdGVlX3NobSAqdGVlX3NobV9maW5kX2J5X3Bh KHN0cnVjdCB0ZWVfZGV2aWNlICp0ZWVkZXYsIHUzMiBmbGFncywKKwkJCXBoeXNfYWRkcl90IHBh KTsKKworLyoqCisgKiB0ZWVfc2htX3ZhMnBhKCkgLSBHZXQgcGh5c2ljYWwgYWRkcmVzcyBvZiBh IHZpcnR1YWwgYWRkcmVzcworICogQHNobToJU2hhcmVkIG1lbW9yeSBoYW5kbGUKKyAqIEB2YToJ CVZpcnR1YWwgYWRkcmVzcyB0byB0cmFubHNhdGUKKyAqIEBwYToJCVJldHVybmVkIHBoeXNpY2Fs IGFkZHJlc3MKKyAqIEByZXR1cm5zIDAgb24gc3VjY2VzcyBhbmQgPCAwIG9uIGZhaWx1cmUKKyAq LworaW50IHRlZV9zaG1fdmEycGEoc3RydWN0IHRlZV9zaG0gKnNobSwgdm9pZCAqdmEsIHBoeXNf YWRkcl90ICpwYSk7CisKKy8qKgorICogdGVlX3NobV9wYTJ2YSgpIC0gR2V0IHZpcnR1YWwgYWRk cmVzcyBvZiBhIHBoeXNpY2FsIGFkZHJlc3MKKyAqIEBzaG06CVNoYXJlZCBtZW1vcnkgaGFuZGxl CisgKiBAcGE6CQlQaHlzaWNhbCBhZGRyZXNzIHRvIHRyYW5sc2F0ZQorICogQHZhOgkJUmV0dXJu ZWQgdmlydHVhbCBhZGRyZXNzCisgKiBAcmV0dXJucyAwIG9uIHN1Y2Nlc3MgYW5kIDwgMCBvbiBm YWlsdXJlCisgKi8KK2ludCB0ZWVfc2htX3BhMnZhKHN0cnVjdCB0ZWVfc2htICpzaG0sIHBoeXNf YWRkcl90IHBhLCB2b2lkICoqdmEpOworCisvKioKKyAqIHRlZV9zaG1fZ2V0X3ZhKCkgLSBHZXQg dmlydHVhbCBhZGRyZXNzIG9mIGEgc2hhcmVkIG1lbW9yeSBwbHVzIGFuIG9mZnNldAorICogQHNo bToJU2hhcmVkIG1lbW9yeSBoYW5kbGUKKyAqIEBvZmZzOglPZmZzZXQgZnJvbSBzdGFydCBvZiB0 aGlzIHNoYXJlZCBtZW1vcnkKKyAqIEByZXR1cm5zIHZpcnR1YWwgYWRkcmVzcyBvZiB0aGUgc2hh cmVkIG1lbW9yeSArIG9mZnMgaWYgb2ZmcyBpcyB3aXRoaW4KKyAqCXRoZSBib3VuZHMgb2YgdGhp cyBzaGFyZWQgbWVtb3J5LCBlbHNlIGFuIEVSUl9QVFIKKyAqLwordm9pZCAqdGVlX3NobV9nZXRf dmEoc3RydWN0IHRlZV9zaG0gKnNobSwgc2l6ZV90IG9mZnMpOworCisvKioKKyAqIHRlZV9zaG1f Z2V0X3BhKCkgLSBHZXQgcGh5c2ljYWwgYWRkcmVzcyBvZiBhIHNoYXJlZCBtZW1vcnkgcGx1cyBh biBvZmZzZXQKKyAqIEBzaG06CVNoYXJlZCBtZW1vcnkgaGFuZGxlCisgKiBAb2ZmczoJT2Zmc2V0 IGZyb20gc3RhcnQgb2YgdGhpcyBzaGFyZWQgbWVtb3J5CisgKiBAcGE6CQlQaHlzaWNhbCBhZGRy ZXNzIHRvIHJldHVybgorICogQHJldHVybnMgMCBpZiBvZmZzIGlzIHdpdGhpbiB0aGUgYm91bmRz IG9mIHRoaXMgc2hhcmVkIG1lbW9yeSwgZWxzZSBhbgorICoJZXJyb3IgY29kZS4KKyAqLworaW50 IHRlZV9zaG1fZ2V0X3BhKHN0cnVjdCB0ZWVfc2htICpzaG0sIHNpemVfdCBvZmZzLCBwaHlzX2Fk ZHJfdCAqcGEpOworCisvKioKKyAqIHRlZV9zaG1fZ2V0X2Zyb21fZmQoKSAtIEdldCBhIHNoYXJl ZCBtZW1vcnkgaGFuZGxlIGZyb20gYSBmaWxlIGRlc2NyaXB0b3IKKyAqIEBmZDoJCUEgdXNlciBz cGFjZSBmaWxlIGRlc2NyaXB0b3IKKyAqCisgKiBUaGlzIGZ1bmN0aW9uIGluY3JlYXNlcyB0aGUg cmVmZXJlbmNlIGNvdW50ZXIgb24gdGhlIHNoYXJlZCBtZW1vcnkgYW5kCisgKiByZXR1cm5zIGEg aGFuZGxlLgorICogQHJldHVybnMgaGFuZGxlIHRvIHNoYXJlZCBtZW1vcnkKKyAqLworc3RydWN0 IHRlZV9zaG0gKnRlZV9zaG1fZ2V0X2Zyb21fZmQoaW50IGZkKTsKKworLyoqCisgKiB0ZWVfc2ht X3B1dCgpIC0gRGVjcmVhc2UgcmVmZXJlbmNlIGNvdW50IG9uIGEgc2hhcmVkIG1lbW9yeSBoYW5k bGUKKyAqIEBzaG06CVNoYXJlZCBtZW1vcnkgaGFuZGxlCisgKi8KK3ZvaWQgdGVlX3NobV9wdXQo c3RydWN0IHRlZV9zaG0gKnNobSk7CisKKy8qKgorICogdGVlX3NobV9nZXRfZmQoKSAtIEluY3Jl YXNlIHJlZmVyZW5jZSBjb3VudCBhbmQgcmV0dXJuIGZpbGUgZGVzY3JpcHRvcgorICogQHNobToJ U2hhcmVkIG1lbW9yeSBoYW5kbGUKKyAqIEByZXR1cm5zIHVzZXIgc3BhY2UgZmlsZSBkZXNjcmlw dG9yIHRvIHNoYXJlZCBtZW1vcnkKKyAqLworaW50IHRlZV9zaG1fZ2V0X2ZkKHN0cnVjdCB0ZWVf c2htICpzaG0pOworCisvKioKKyAqIHRlZV9zaG1fcHV0X2ZkKCkgLSBEZWNyZWFzZSByZWZlcmVu Y2UgY291bnQgYW5kIGNsb3NlIGZpbGUgZGVzY3JpcHRvcgorICogQGZkOgkJRmlsZSBkZXNjcmlw dG9yIHRvIGNsb3NlCisgKiBAcmV0dXJucyA8IDAgb24gZmFpbHVyZQorICovCitpbnQgdGVlX3No bV9wdXRfZmQoaW50IGZkKTsKKworI2VuZGlmIC8qX19URUVfRFJWX0gqLwpkaWZmIC0tZ2l0IGEv aW5jbHVkZS91YXBpL2xpbnV4L3RlZS5oIGIvaW5jbHVkZS91YXBpL2xpbnV4L3RlZS5oCm5ldyBm aWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAuLjMxOWNjNjEKLS0tIC9kZXYvbnVsbAorKysg Yi9pbmNsdWRlL3VhcGkvbGludXgvdGVlLmgKQEAgLTAsMCArMSwzODMgQEAKKy8qCisgKiBDb3B5 cmlnaHQgKGMpIDIwMTUsIExpbmFybyBMaW1pdGVkCisgKgorICogVGhpcyBzb2Z0d2FyZSBpcyBs aWNlbnNlZCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYworICogTGlj ZW5zZSB2ZXJzaW9uIDIsIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0 aW9uLCBhbmQKKyAqIG1heSBiZSBjb3BpZWQsIGRpc3RyaWJ1dGVkLCBhbmQgbW9kaWZpZWQgdW5k ZXIgdGhvc2UgdGVybXMuCisgKgorICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRo ZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCisgKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFO VFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgorICogTUVSQ0hBTlRBQklM SVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQorICogR05V IEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KKyAqCisgKi8KKworI2lm bmRlZiBfX1RFRV9ICisjZGVmaW5lIF9fVEVFX0gKKworI2luY2x1ZGUgPGxpbnV4L2lvY3RsLmg+ CisjaW5jbHVkZSA8bGludXgvdHlwZXMuaD4KKworLyoKKyAqIFRoaXMgZmlsZSBkZXNjcmliZXMg dGhlIEFQSSBwcm92aWRlZCBieSBhIFRFRSBkcml2ZXIgdG8gdXNlciBzcGFjZS4KKyAqCisgKiBF YWNoIFRFRSBkcml2ZXIgZGVmaW5lcyBhIFRFRSBzcGVjaWZpYyBwcm90b2NvbCB3aGljaCBpcyB1 c2VkIGZvciB0aGUKKyAqIGRhdGEgcGFzc2VkIGJhY2sgYW5kIGZvcnRoIHVzaW5nIFRFRV9JT0Nf Q01ELgorICovCisKKworLyogSGVscGVycyB0byBtYWtlIHRoZSBpb2N0bCBkZWZpbmVzICovCisj ZGVmaW5lIFRFRV9JT0NfTUFHSUMJMHhhNAorI2RlZmluZSBURUVfSU9DX0JBU0UJMAorCisvKiBG bGFncyByZWxhdGluZyB0byBzaGFyZWQgbWVtb3J5ICovCisjZGVmaW5lIFRFRV9JT0NUTF9TSE1f TUFQUEVECTB4MQkvKiBtZW1vcnkgbWFwcGVkIGluIG5vcm1hbCB3b3JsZCAqLworI2RlZmluZSBU RUVfSU9DVExfU0hNX0RNQV9CVUYJMHgyCS8qIGRtYS1idWYgaGFuZGxlIG9uIHNoYXJlZCBtZW1v cnkgKi8KKworI2RlZmluZSBURUVfTUFYX0FSR19TSVpFCTEwMjQKKworI2RlZmluZSBURUVfR0VO X0NBUF9HUAkJKDEgPDwgMCkvKiBHbG9iYWwgUGxhdGZvcm0gY29tcGxpYW50IFRFRSAqLworCisv KgorICogVEVFIEltcGxlbWVudGF0aW9uIElECisgKi8KKyNkZWZpbmUgVEVFX0lNUExfSURfT1BU RUUJMQorCisvKgorICogT1AtVEVFIHNwZWNpZmljIGNhcGFiaWxpdGllcworICovCisjZGVmaW5l IFRFRV9PUFRFRV9DQVBfVFoJKDEgPDwgMCkKKworLyoqCisgKiBzdHJ1Y3QgdGVlX2lvY3RsX3Zl cnNpb25fZGF0YSAtIFRFRSB2ZXJzaW9uCisgKiBAaW1wbF9pZDoJW291dF0gVEVFIGltcGxlbWVu dGF0aW9uIGlkCisgKiBAaW1wbF9jYXBzOglbb3V0XSBJbXBsZW1lbnRhdGlvbiBzcGVjaWZpYyBj YXBhYmlsaXRpZXMKKyAqIEBnZW5fY2FwczoJW291dF0gR2VuZXJpYyBjYXBhYmlsaXRpZXMsIGRl ZmluZWQgYnkgVEVFX0dFTl9DQVBTXyogYWJvdmUKKyAqCisgKiBJZGVudGlmaWVzIHRoZSBURUUg aW1wbGVtZW50YWlvbiwgQGltcGxfaWQgaXMgb25lIG9mIFRFRV9JTVBMX0lEXyogYWJvdmUuCisg KiBAaW1wbF9jYXBzIGlzIGltcGxlbWVudGF0aW9uIHNwZWNpZmljLCBmb3IgZXhhbXBsZSBURUVf T1BURUVfQ0FQXyoKKyAqIGlzIHZhbGlkIHdoZW4gQGltcGxfaWQgPT0gVEVFX0lNUExfSURfT1BU RUUuCisgKi8KK3N0cnVjdCB0ZWVfaW9jdGxfdmVyc2lvbl9kYXRhIHsKKwlfX3UzMiBpbXBsX2lk OworCV9fdTMyIGltcGxfY2FwczsKKwlfX3UzMiBnZW5fY2FwczsKK307CisvKioKKyAqIFRFRV9J T0NfVkVSU0lPTiAtIHF1ZXJ5IHZlcnNpb24gb2YgVEVFCisgKgorICogVGFrZXMgYSB0ZWVfdmVy c2lvbiBzdHJ1Y3QgYW5kIHJldHVybnMgd2l0aCB0aGUgVEVFIHZlcnNpb24gZGF0YSBmaWxsZWQK KyAqIGluLgorICovCisjZGVmaW5lIFRFRV9JT0NfVkVSU0lPTgkJX0lPUihURUVfSU9DX01BR0lD LCBURUVfSU9DX0JBU0UgKyAwLCBcCisJCQkJICAgICBzdHJ1Y3QgdGVlX2lvY3RsX3ZlcnNpb25f ZGF0YSkKKworLyoqCisgKiBzdHJ1Y3QgdGVlX2lvY3RsX3NobV9hbGxvY19kYXRhIC0gU2hhcmVk IG1lbW9yeSBhbGxvY2F0ZSBhcmd1bWVudAorICogQHNpemU6CVtpbi9vdXRdIFNpemUgb2Ygc2hh cmVkIG1lbW9yeSB0byBhbGxvY2F0ZQorICogQGZsYWdzOglbaW4vb3V0XSBGbGFncyB0by9mcm9t IGFsbG9jYXRpb24uCisgKiBAZmQ6CQlbb3V0XSBkbWFfYnVmIGZpbGUgZGVzY3JpcHRvciBvZiB0 aGUgc2hhcmVkIG1lbW9yeQorICoKKyAqIFRoZSBmbGFncyBmaWVsZCBzaG91bGQgY3VycmVudGx5 IGJlIHplcm8gYXMgaW5wdXQuIFVwZGF0ZWQgYnkgdGhlIGNhbGwKKyAqIHdpdGggYWN0dWFsIGZs YWdzIGFzIGRlZmluZWQgYnkgVEVFX0lPQ1RMX1NITV8qIGFib3ZlLgorICogVGhpcyBzdHJ1Y3R1 cmUgaXMgdXNlZCBhcyBhcmd1bWVudCBmb3IgVEVFX0lPQ19TSE1fQUxMT0MgYmVsb3cuCisgKi8K K3N0cnVjdCB0ZWVfaW9jdGxfc2htX2FsbG9jX2RhdGEgeworCV9fdTY0IHNpemU7CisJX191MzIg ZmxhZ3M7CisJX19zMzIgZmQ7Cit9OworLyoqCisgKiBURUVfSU9DX1NITV9BTExPQyAtIGFsbG9j YXRlIHNoYXJlZCBtZW1vcnkKKyAqCisgKiBBbGxvY2F0ZXMgc2hhcmVkIG1lbW9yeSBiZXR3ZWVu IHRoZSB1c2VyIHNwYWNlIHByb2Nlc3MgYW5kIHNlY3VyZSBPUy4KKyAqIFRoZSByZXR1cm5lZCBm aWxlIGRlc2NyaXB0b3IgaXMgdXNlZCB0byBtYXAgdGhlIHNoYXJlZCBtZW1vcnkgaW50byB1c2Vy CisgKiBzcGFjZS4gVGhlIHNoYXJlZCBtZW1vcnkgaXMgZnJlZWQgd2hlbiB0aGUgZGVzY3JpcHRv ciBpcyBjbG9zZWQgYW5kIHRoZQorICogbWVtb3J5IGlzIHVubWFwcGVkLgorICovCisjZGVmaW5l IFRFRV9JT0NfU0hNX0FMTE9DCV9JT1dSKFRFRV9JT0NfTUFHSUMsIFRFRV9JT0NfQkFTRSArIDEs IFwKKwkJCQkgICAgIHN0cnVjdCB0ZWVfaW9jdGxfc2htX2FsbG9jX2RhdGEpCisKKy8qKgorICog c3RydWN0IHRlZV9pb2N0bF9idWZfZGF0YSAtIFZhcmlhYmxlIHNpemVkIGJ1ZmZlcgorICogQGJ1 Zl9wdHI6CVtpbl0gQSBfX3VzZXIgcG9pbnRlciB0byBhIGJ1ZmZlcgorICogQGJ1Zl9sZW46CVtp bl0gTGVuZ3RoIG9mIHRoZSBidWZmZXIgYWJvdmUKKyAqCisgKiBVc2VkIGFzIGFyZ3VtZW50IGZv ciBURUVfSU9DX09QRU5fU0VTU0lPTiwgVEVFX0lPQ19JTlZPS0UsCisgKiBURUVfSU9DX1NVUFBM X1JFQ1YsIGFuZCBURUVfSU9DX1NVUFBMX1NFTkQgYmVsb3cuCisgKi8KK3N0cnVjdCB0ZWVfaW9j dGxfYnVmX2RhdGEgeworCV9fdTY0IGJ1Zl9wdHI7CisJX191NjQgYnVmX2xlbjsKK307CisKKwor LyoKKyAqIEF0dHJpYnV0ZXMgZm9yIHN0cnVjdCB0ZWVfaW9jdGxfcGFyYW0sIHNlbGVjdHMgZmll bGQgaW4gdGhlIHVuaW9uCisgKi8KKyNkZWZpbmUgVEVFX0lPQ1RMX1BBUkFNX0FUVFJfVFlQRV9O T05FCQkwCS8qIHBhcmFtZXRlciBub3QgdXNlZCAqLworCisvKgorICogVGhlc2UgZGVmaW5lcyB2 YWx1ZSBwYXJhbWV0ZXJzIChzdHJ1Y3QgdGVlX2lvY3RsX3BhcmFtX3ZhbHVlKQorICovCisjZGVm aW5lIFRFRV9JT0NUTF9QQVJBTV9BVFRSX1RZUEVfVkFMVUVfSU5QVVQJMQorI2RlZmluZSBURUVf SU9DVExfUEFSQU1fQVRUUl9UWVBFX1ZBTFVFX09VVFBVVAkyCisjZGVmaW5lIFRFRV9JT0NUTF9Q QVJBTV9BVFRSX1RZUEVfVkFMVUVfSU5PVVQJMwkvKiBpbnB1dCBhbmQgb3V0cHV0ICovCisKKy8q CisgKiBUaGVzZSBkZWZpbmVzIHNoYXJlZCBtZW1vcnkgcmVmZXJlbmNlIHBhcmFtZXRlcnMgKHN0 cnVjdAorICogdGVlX2lvY3RsX3BhcmFtX21lbXJlZikKKyAqLworI2RlZmluZSBURUVfSU9DVExf UEFSQU1fQVRUUl9UWVBFX01FTVJFRl9JTlBVVAk1CisjZGVmaW5lIFRFRV9JT0NUTF9QQVJBTV9B VFRSX1RZUEVfTUVNUkVGX09VVFBVVAk2CisjZGVmaW5lIFRFRV9JT0NUTF9QQVJBTV9BVFRSX1RZ UEVfTUVNUkVGX0lOT1VUCTcJLyogaW5wdXQgYW5kIG91dHB1dCAqLworCisvKgorICogTWFzayBm b3IgdGhlIHR5cGUgcGFydCBvZiB0aGUgYXR0cmlidXRlLCBsZWF2ZXMgcm9vbSBmb3IgbW9yZSB0 eXBlcworICovCisjZGVmaW5lIFRFRV9JT0NUTF9QQVJBTV9BVFRSX1RZUEVfTUFTSwkJMHhmZgor CisvKgorICogTWF0Y2hlcyBURUVDX0xPR0lOXyogaW4gR1AgVEVFIENsaWVudCBBUEkKKyAqIElz IG9ubHkgZGVmaW5lZCBmb3IgR1AgY29tcGxpYW50IFRFRXMKKyAqLworI2RlZmluZSBURUVfSU9D VExfTE9HSU5fUFVCTElDCQkJMAorI2RlZmluZSBURUVfSU9DVExfTE9HSU5fVVNFUgkJCTEKKyNk ZWZpbmUgVEVFX0lPQ1RMX0xPR0lOX0dST1VQCQkJMgorI2RlZmluZSBURUVfSU9DVExfTE9HSU5f QVBQTElDQVRJT04JCTQKKyNkZWZpbmUgVEVFX0lPQ1RMX0xPR0lOX1VTRVJfQVBQTElDQVRJT04J NQorI2RlZmluZSBURUVfSU9DVExfTE9HSU5fR1JPVVBfQVBQTElDQVRJT04JNgorCisvKioKKyAq IHN0cnVjdCB0ZWVfaW9jdGxfcGFyYW1fbWVtcmVmIC0gbWVtb3J5IHJlZmVyZW5jZQorICogQHNo bV9vZmZzOglPZmZzZXQgaW50byB0aGUgc2hhcmVkIG1lbW9yeSBvYmplY3QKKyAqIEBzaXplOglT aXplIG9mIHRoZSBidWZmZXIKKyAqIEBzaG1fZmQ6CVNoYXJlZCBtZW1vcnkgZmlsZSBkZXNjcmlw dG9yCisgKgorICogU2hhcmVkIG1lbW9yeSBpcyBhbGxvY2F0ZWQgd2l0aCBURUVfSU9DX1NITV9B TExPQyB3aGljaCByZXR1cm5zIGEgZmlsZQorICogZGVzY3JpcHRvciBjb25uZWN0ZWQgdG8gdGhl IHNoYXJlZCBtZW1vcnkgb2JqZWN0LiBBIG1lbXJlZiBjYW4gcmVmZXJlbmNlCisgKiBhIHBhcnQg b2YgYSBzaGFyZWQgbWVtb3J5IGJ5IHNwZWNpZnlpbmcgYW4gb2Zmc2V0IChAc2htX29mZnMpIGFu ZCBAc2l6ZQorICogb2YgdGhlIG9iamVjdC4gVG8gc3VwcGx5IHRoZSBlbnRpcmUgc2hhcmVkIG1l bW9yeSBvYmplY3Qgc2V0IEBzaG1fb2ZmcyB0byAwCisgKiBhbmQgQHNpemUgdG8gdGhlIHByZXZp b3VzbHkgcmV0dXJuZWQgc2l6ZSBvZiB0aGUgb2JqZWN0LgorICovCitzdHJ1Y3QgdGVlX2lvY3Rs X3BhcmFtX21lbXJlZiB7CisJX191NjQgc2htX29mZnM7CisJX191NjQgc2l6ZTsKKwlfX3M2NCBz aG1fZmQ7Cit9OworCisvKioKKyAqIHN0cnVjdCB0ZWVfaW9jdGxfcGFyYW1fdmFsdWUgLSB2YWx1 ZXMKKyAqIEBhOiBmaXJzdCB2YWx1ZQorICogQGI6IHNlY29uZCB2YWx1ZQorICogQGM6IHRoaXJk IHZhbHVlCisgKi8KK3N0cnVjdCB0ZWVfaW9jdGxfcGFyYW1fdmFsdWUgeworCV9fdTY0IGE7CisJ X191NjQgYjsKKwlfX3U2NCBjOworfTsKKworLyoqCisgKiBzdHJ1Y3QgdGVlX2lvY3RsX3BhcmFt IC0gcGFyYW1ldGVyCisgKiBAYXR0cjogYXR0cmlidXRlcworICogQG1lbXJlZjogYSBtZW1vcnkg cmVmZXJlbmNlCisgKiBAdmFsdWU6IGEgdmFsdWUKKyAqCisgKiBAYXR0ciAmIFRFRV9QQVJBTV9B VFRSX1RZUEVfTUFTSyBpbmRpY2F0ZXMgaWYgbWVtcmVmIG9yIHZhbHVlIGlzIHVzZWQgaW4KKyAq IHRoZSB1bmlvbi4gVEVFX1BBUkFNX0FUVFJfVFlQRV9WQUxVRV8qIGluZGljYXRlcyB2YWx1ZSBh bmQKKyAqIFRFRV9QQVJBTV9BVFRSX1RZUEVfTUVNUkVGXyogaW5kaWNhdGVzIG1lbXJlZi4gVEVF X1BBUkFNX0FUVFJfVFlQRV9OT05FCisgKiBpbmRpY2F0ZXMgdGhhdCBub25lIG9mIHRoZSBtZW1i ZXJzIGFyZSB1c2VkLgorICovCitzdHJ1Y3QgdGVlX2lvY3RsX3BhcmFtIHsKKwlfX3U2NCBhdHRy OworCXVuaW9uIHsKKwkJc3RydWN0IHRlZV9pb2N0bF9wYXJhbV9tZW1yZWYgbWVtcmVmOworCQlz dHJ1Y3QgdGVlX2lvY3RsX3BhcmFtX3ZhbHVlIHZhbHVlOworCX0gdTsKK307CisKKyNkZWZpbmUg VEVFX0lPQ1RMX1VVSURfTEVOCQkxNgorCisvKioKKyAqIHN0cnVjdCB0ZWVfaW9jdGxfb3Blbl9z ZXNzaW9uX2FyZyAtIE9wZW4gc2Vzc2lvbiBhcmd1bWVudAorICogQHV1aWQ6CVtpbl0gVVVJRCBv ZiB0aGUgVHJ1c3RlZCBBcHBsaWNhdGlvbgorICogQGNsbnRfdXVpZDoJW2luXSBVVUlEIG9mIGNs aWVudAorICogQGNsbnRfbG9naW46CVtpbl0gTG9naW4gY2xhc3Mgb2YgY2xpZW50LCBURUVfTE9H SU5fKiBhYm92ZQorICogQGNhbmNlbF9pZDoJW2luXSBDYW5jZWxsYXRpb24gaWQsIGEgdW5pcXVl IHZhbHVlIHRvIGlkZW50aWZ5IHRoaXMgcmVxdWVzdAorICogQHNlc3Npb246CVtvdXRdIFNlc3Np b24gaWQKKyAqIEByZXQ6CVtvdXRdIHJldHVybiB2YWx1ZQorICogQHJldF9vcmlnaW4JW291dF0g b3JpZ2luIG9mIHRoZSByZXR1cm4gdmFsdWUKKyAqIEBudW1fcGFyYW1zCVtpbl0gbnVtYmVyIG9m IHBhcmFtZXRlcnMgZm9sbG93aW5nIHRoaXMgc3RydWN0CisgKi8KK3N0cnVjdCB0ZWVfaW9jdGxf b3Blbl9zZXNzaW9uX2FyZyB7CisJX191OCB1dWlkW1RFRV9JT0NUTF9VVUlEX0xFTl07CisJX191 OCBjbG50X3V1aWRbVEVFX0lPQ1RMX1VVSURfTEVOXTsKKwlfX3UzMiBjbG50X2xvZ2luOworCV9f dTMyIGNhbmNlbF9pZDsKKwlfX3UzMiBzZXNzaW9uOworCV9fdTMyIHJldDsKKwlfX3UzMiByZXRf b3JpZ2luOworCV9fdTMyIG51bV9wYXJhbXM7CisJLyoKKwkgKiB0aGlzIHN0cnVjdCBpcyA4IGJ5 dGUgYWxpZ25lZCBzaW5jZSB0aGUgJ3N0cnVjdCB0ZWVfaW9jdGxfcGFyYW0nCisJICogd2hpY2gg Zm9sbG93cyByZXF1aXJlcyA4IGJ5dGUgYWxpZ25tZW50LgorCSAqCisJICogQ29tbWVudGVkIG91 dCBlbGVtZW50IHVzZWQgdG8gdmlzdWFsaXplIHRoZSBsYXlvdXQgZHluYW1pYyBwYXJ0CisJICog b2YgdGhlIHN0cnVjdC4gVGhpcyBmaWVsZCBpcyBub3QgYXZhaWxhYmxlIGF0IGFsbCBpZgorCSAq IG51bV9wYXJhbXMgPT0gMC4KKwkgKgorCSAqIHN0cnVjdCB0ZWVfaW9jdGxfcGFyYW0gcGFyYW1z W251bV9wYXJhbXNdOworCSAqLworfSBfX2FsaWduZWQoOCk7CisKKy8qKgorICogVEVFX0lPQ19P UEVOX1NFU1NJT04gLSBvcGVucyBhIHNlc3Npb24gdG8gYSBUcnVzdGVkIEFwcGxpY2F0aW9uCisg KgorICogVGFrZXMgYSBzdHJ1Y3QgdGVlX2lvY3RsX2J1Zl9kYXRhIHdoaWNoIGNvbnRhaW5zIGEg c3RydWN0CisgKiB0ZWVfaW9jdGxfb3Blbl9zZXNzaW9uX2FyZyBmb2xsb3dlZCBieSBhbnkgYXJy YXkgb2Ygc3RydWN0CisgKiB0ZWVfaW9jdGxfcGFyYW0KKyAqLworI2RlZmluZSBURUVfSU9DX09Q RU5fU0VTU0lPTglfSU9SKFRFRV9JT0NfTUFHSUMsIFRFRV9JT0NfQkFTRSArIDIsIFwKKwkJCQkg ICAgIHN0cnVjdCB0ZWVfaW9jdGxfYnVmX2RhdGEpCisKKy8qKgorICogc3RydWN0IHRlZV9pb2N0 bF9pbnZva2VfZnVuY19hcmcgLSBJbnZva2VzIGEgZnVuY3Rpb24gaW4gYSBUcnVzdGVkIEFwcGxp Y2F0aW9uCisgKiBAZnVuYzoJW2luXSBUcnVzdGVkIEFwcGxpY2F0aW9uIGZ1bmN0aW9uLCBzcGVj aWZpYyB0byB0aGUgVEEKKyAqIEBzZXNzaW9uOglbaW5dIFNlc3Npb24gaWQKKyAqIEBjYW5jZWxf aWQ6CVtpbl0gQ2FuY2VsbGF0aW9uIGlkLCBhIHVuaXF1ZSB2YWx1ZSB0byBpZGVudGlmeSB0aGlz IHJlcXVlc3QKKyAqIEByZXQ6CVtvdXRdIHJldHVybiB2YWx1ZQorICogQHJldF9vcmlnaW4JW291 dF0gb3JpZ2luIG9mIHRoZSByZXR1cm4gdmFsdWUKKyAqIEBudW1fcGFyYW1zCVtpbl0gbnVtYmVy IG9mIHBhcmFtZXRlcnMgZm9sbG93aW5nIHRoaXMgc3RydWN0CisgKi8KK3N0cnVjdCB0ZWVfaW9j dGxfaW52b2tlX2FyZyB7CisJX191MzIgZnVuYzsKKwlfX3UzMiBzZXNzaW9uOworCV9fdTMyIGNh bmNlbF9pZDsKKwlfX3UzMiByZXQ7CisJX191MzIgcmV0X29yaWdpbjsKKwlfX3UzMiBudW1fcGFy YW1zOworCS8qCisJICogdGhpcyBzdHJ1Y3QgaXMgOCBieXRlIGFsaWduZWQgc2luY2UgdGhlICdz dHJ1Y3QgdGVlX2lvY3RsX3BhcmFtJworCSAqIHdoaWNoIGZvbGxvd3MgcmVxdWlyZXMgOCBieXRl IGFsaWdubWVudC4KKwkgKgorCSAqIENvbW1lbnRlZCBvdXQgZWxlbWVudCB1c2VkIHRvIHZpc3Vh bGl6ZSB0aGUgbGF5b3V0IGR5bmFtaWMgcGFydAorCSAqIG9mIHRoZSBzdHJ1Y3QuIFRoaXMgZmll bGQgaXMgbm90IGF2YWlsYWJsZSBhdCBhbGwgaWYKKwkgKiBudW1fcGFyYW1zID09IDAuCisJICoK KwkgKiBzdHJ1Y3QgdGVlX2lvY3RsX3BhcmFtIHBhcmFtc1tudW1fcGFyYW1zXTsKKwkgKi8KK30g X19hbGlnbmVkKDgpOworCisvKioKKyAqIFRFRV9JT0NfSU5WT0tFIC0gSW52b2tlcyBhIGZ1bmN0 aW9uIGluIGEgVHJ1c3RlZCBBcHBsaWNhdGlvbgorICoKKyAqIFRha2VzIGEgc3RydWN0IHRlZV9p b2N0bF9idWZfZGF0YSB3aGljaCBjb250YWlucyBhIHN0cnVjdAorICogdGVlX2ludm9rZV9mdW5j X2FyZyBmb2xsb3dlZCBieSBhbnkgYXJyYXkgb2Ygc3RydWN0IHRlZV9wYXJhbQorICovCisjZGVm aW5lIFRFRV9JT0NfSU5WT0tFCQlfSU9SKFRFRV9JT0NfTUFHSUMsIFRFRV9JT0NfQkFTRSArIDMs IFwKKwkJCQkgICAgIHN0cnVjdCB0ZWVfaW9jdGxfYnVmX2RhdGEpCisKKy8qKgorICogc3RydWN0 IHRlZV9pb2N0bF9jYW5jZWxfYXJnIC0gQ2FuY2VscyBhbiBvcGVuIHNlc3Npb24gb3IgaW52b2tl IGlvY3RsCisgKiBAY2FuY2VsX2lkOglbaW5dIENhbmNlbGxhdGlvbiBpZCwgYSB1bmlxdWUgdmFs dWUgdG8gaWRlbnRpZnkgdGhpcyByZXF1ZXN0CisgKiBAc2Vzc2lvbjoJW2luXSBTZXNzaW9uIGlk LCBpZiB0aGUgc2Vzc2lvbiBpcyBvcGVuZWQsIGVsc2Ugc2V0IHRvIDAKKyAqLworc3RydWN0IHRl ZV9pb2N0bF9jYW5jZWxfYXJnIHsKKwlfX3UzMiBjYW5jZWxfaWQ7CisJX191MzIgc2Vzc2lvbjsK K307CisvKioKKyAqIFRFRV9JT0NfQ0FOQ0VMIC0gQ2FuY2VscyBhbiBvcGVuIHNlc3Npb24gb3Ig aW52b2tlCisgKi8KKyNkZWZpbmUgVEVFX0lPQ19DQU5DRUwJCV9JT1IoVEVFX0lPQ19NQUdJQywg VEVFX0lPQ19CQVNFICsgNCwgXAorCQkJCSAgICAgc3RydWN0IHRlZV9pb2N0bF9jYW5jZWxfYXJn KQorCisvKioKKyAqIHN0cnVjdCB0ZWVfaW9jdGxfY2xvc2Vfc2Vzc2lvbl9hcmcgLSBDbG9zZXMg YW4gb3BlbiBzZXNzaW9uCisgKiBAc2Vzc2lvbjoJW2luXSBTZXNzaW9uIGlkCisgKi8KK3N0cnVj dCB0ZWVfaW9jdGxfY2xvc2Vfc2Vzc2lvbl9hcmcgeworCV9fdTMyIHNlc3Npb247Cit9OworLyoq CisgKiBURUVfSU9DX0NMT1NFX1NFU1NJT04gLSBDbG9zZXMgYSBzZXNzaW9uCisgKi8KKyNkZWZp bmUgVEVFX0lPQ19DTE9TRV9TRVNTSU9OCV9JT1IoVEVFX0lPQ19NQUdJQywgVEVFX0lPQ19CQVNF ICsgNSwgXAorCQkJCSAgICAgc3RydWN0IHRlZV9pb2N0bF9jbG9zZV9zZXNzaW9uX2FyZykKKwor LyoqCisgKiBzdHJ1Y3QgdGVlX2lvY2xfc3VwcF9yZWN2X2FyZyAtIFJlY2VpdmUgYSByZXF1ZXN0 IGZvciBhIHN1cHBsaWNhbnQgZnVuY3Rpb24KKyAqIEBmdW5jOglbaW5dIHN1cHBsaWNhbnQgZnVu Y3Rpb24KKyAqIEBudW1fcGFyYW1zCVtpbi9vdXRdIG51bWJlciBvZiBwYXJhbWV0ZXJzIGZvbGxv d2luZyB0aGlzIHN0cnVjdAorICoKKyAqIEBudW1fcGFyYW1zIGlzIHRoZSBudW1iZXIgb2YgcGFy YW1zIHRoYXQgdGVlLXN1cHBsaWNhbnQgaGFzIHJvb20gdG8KKyAqIHJlY2VpdmUgd2hlbiBpbnB1 dCwgQG51bV9wYXJhbXMgaXMgdGhlIG51bWJlciBvZiBhY3R1YWwgcGFyYW1zCisgKiB0ZWUtc3Vw cGxpY2FudCByZWNlaXZlcyB3aGVuIG91dHB1dC4KKyAqLworc3RydWN0IHRlZV9pb2NsX3N1cHBf cmVjdl9hcmcgeworCV9fdTMyIGZ1bmM7CisJX191MzIgbnVtX3BhcmFtczsKKwkvKgorCSAqIHRo aXMgc3RydWN0IGlzIDggYnl0ZSBhbGlnbmVkIHNpbmNlIHRoZSAnc3RydWN0IHRlZV9pb2N0bF9w YXJhbScKKwkgKiB3aGljaCBmb2xsb3dzIHJlcXVpcmVzIDggYnl0ZSBhbGlnbm1lbnQuCisJICoK KwkgKiBDb21tZW50ZWQgb3V0IGVsZW1lbnQgdXNlZCB0byB2aXN1YWxpemUgdGhlIGxheW91dCBk eW5hbWljIHBhcnQKKwkgKiBvZiB0aGUgc3RydWN0LiBUaGlzIGZpZWxkIGlzIG5vdCBhdmFpbGFi bGUgYXQgYWxsIGlmCisJICogbnVtX3BhcmFtcyA9PSAwLgorCSAqCisJICogc3RydWN0IHRlZV9p b2N0bF9wYXJhbSBwYXJhbXNbbnVtX3BhcmFtc107CisJICovCit9IF9fYWxpZ25lZCg4KTsKKy8q KgorICogVEVFX0lPQ19TVVBQTF9SRUNWIC0gUmVjZWl2ZSBhIHJlcXVlc3QgZm9yIGEgc3VwcGxp Y2FudCBmdW5jdGlvbgorICoKKyAqIFRha2VzIGEgc3RydWN0IHRlZV9pb2N0bF9idWZfZGF0YSB3 aGljaCBjb250YWlucyBhIHN0cnVjdAorICogdGVlX2lvY2xfc3VwcF9yZWN2X2FyZyBmb2xsb3dl ZCBieSBhbnkgYXJyYXkgb2Ygc3RydWN0IHRlZV9wYXJhbQorICovCisjZGVmaW5lIFRFRV9JT0Nf U1VQUExfUkVDVglfSU9SKFRFRV9JT0NfTUFHSUMsIFRFRV9JT0NfQkFTRSArIDYsIFwKKwkJCQkg ICAgIHN0cnVjdCB0ZWVfaW9jdGxfYnVmX2RhdGEpCisKKworLyoqCisgKiBzdHJ1Y3QgdGVlX2lv Y2xfc3VwcF9zZW5kX2FyZyAtIFNlbmQgYSByZXNwb25zZSB0byBhIHJlY2VpdmVkIHJlcXVlc3QK KyAqIEByZXQ6CVtvdXRdIHJldHVybiB2YWx1ZQorICogQG51bV9wYXJhbXMJW2luXSBudW1iZXIg b2YgcGFyYW1ldGVycyBmb2xsb3dpbmcgdGhpcyBzdHJ1Y3QKKyAqLworc3RydWN0IHRlZV9pb2Ns X3N1cHBfc2VuZF9hcmcgeworCV9fdTMyIHJldDsKKwlfX3UzMiBudW1fcGFyYW1zOworCS8qCisJ ICogdGhpcyBzdHJ1Y3QgaXMgOCBieXRlIGFsaWduZWQgc2luY2UgdGhlICdzdHJ1Y3QgdGVlX2lv Y3RsX3BhcmFtJworCSAqIHdoaWNoIGZvbGxvd3MgcmVxdWlyZXMgOCBieXRlIGFsaWdubWVudC4K KwkgKgorCSAqIENvbW1lbnRlZCBvdXQgZWxlbWVudCB1c2VkIHRvIHZpc3VhbGl6ZSB0aGUgbGF5 b3V0IGR5bmFtaWMgcGFydAorCSAqIG9mIHRoZSBzdHJ1Y3QuIFRoaXMgZmllbGQgaXMgbm90IGF2 YWlsYWJsZSBhdCBhbGwgaWYKKwkgKiBudW1fcGFyYW1zID09IDAuCisJICoKKwkgKiBzdHJ1Y3Qg dGVlX2lvY3RsX3BhcmFtIHBhcmFtc1tudW1fcGFyYW1zXTsKKwkgKi8KK30gX19hbGlnbmVkKDgp OworLyoqCisgKiBURUVfSU9DX1NVUFBMX1NFTkQgLSBSZWNlaXZlIGEgcmVxdWVzdCBmb3IgYSBz dXBwbGljYW50IGZ1bmN0aW9uCisgKgorICogVGFrZXMgYSBzdHJ1Y3QgdGVlX2lvY3RsX2J1Zl9k YXRhIHdoaWNoIGNvbnRhaW5zIGEgc3RydWN0CisgKiB0ZWVfaW9jbF9zdXBwX3NlbmRfYXJnIGZv bGxvd2VkIGJ5IGFueSBhcnJheSBvZiBzdHJ1Y3QgdGVlX3BhcmFtCisgKi8KKyNkZWZpbmUgVEVF X0lPQ19TVVBQTF9TRU5ECV9JT1IoVEVFX0lPQ19NQUdJQywgVEVFX0lPQ19CQVNFICsgNywgXAor CQkJCSAgICAgc3RydWN0IHRlZV9pb2N0bF9idWZfZGF0YSkKKworCisvKgorICogRml2ZSBzeXNj YWxscyBhcmUgdXNlZCB3aGVuIGNvbW11bmljYXRpbmcgd2l0aCB0aGUgVEVFIGRyaXZlci4KKyAq IG9wZW4oKTogb3BlbnMgdGhlIGRldmljZSBhc3NvY2lhdGVkIHdpdGggdGhlIGRyaXZlcgorICog aW9jdGwoKTogYXMgZGVzY3JpYmVkIGFib3ZlIG9wZXJhdGluZyBvbiB0aGUgZmlsZSBkZXNjcmlw dG9yIGZyb20gb3BlbigpCisgKiBjbG9zZSgpOiB0d28gY2FzZXMKKyAqICAgLSBjbG9zZXMgdGhl IGRldmljZSBmaWxlIGRlc2NyaXB0b3IKKyAqICAgLSBjbG9zZXMgYSBmaWxlIGRlc2NyaXB0b3Ig Y29ubmVjdGVkIHRvIGFsbG9jYXRlZCBzaGFyZWQgbWVtb3J5CisgKiBtbWFwKCk6IG1hcHMgc2hh cmVkIG1lbW9yeSBpbnRvIHVzZXIgc3BhY2UgdXNpbmcgaW5mb3JtYXRpb24gZnJvbSBzdHJ1Y3QK KyAqCSAgIHRlZV9pb2N0bF9zaG1fYWxsb2NfZGF0YQorICogbXVubWFwKCk6IHVubWFwcyBwcmV2 aW91c2x5IHNoYXJlZCBtZW1vcnkKKyAqLworCisjZW5kaWYgLypfX1RFRV9IKi8KLS0gCjEuOS4x CgoKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KbGludXgt YXJtLWtlcm5lbCBtYWlsaW5nIGxpc3QKbGludXgtYXJtLWtlcm5lbEBsaXN0cy5pbmZyYWRlYWQu b3JnCmh0dHA6Ly9saXN0cy5pbmZyYWRlYWQub3JnL21haWxtYW4vbGlzdGluZm8vbGludXgtYXJt LWtlcm5lbAo= From mboxrd@z Thu Jan 1 00:00:00 1970 From: jens.wiklander@linaro.org (Jens Wiklander) Date: Mon, 1 Feb 2016 10:15:38 +0100 Subject: [PATCH v7 2/4] tee: generic TEE subsystem In-Reply-To: <1454318140-7962-1-git-send-email-jens.wiklander@linaro.org> References: <1454318140-7962-1-git-send-email-jens.wiklander@linaro.org> Message-ID: <1454318140-7962-3-git-send-email-jens.wiklander@linaro.org> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Initial patch for generic TEE subsystem. This subsystem provides: * Registration/un-registration of TEE drivers. * Shared memory between normal world and secure world. * Ioctl interface for interaction with user space. * Sysfs implementation_id of TEE driver A TEE (Trusted Execution Environment) driver is a driver that interfaces with a trusted OS running in some secure environment, for example, TrustZone on ARM cpus, or a separate secure co-processor etc. The TEE subsystem can serve a TEE driver for a Global Platform compliant TEE, but it's not limited to only Global Platform TEEs. This patch builds on other similar implementations trying to solve the same problem: * "optee_linuxdriver" by among others Jean-michel DELORME and Emmanuel MICHEL * "Generic TrustZone Driver" by Javier Gonz?lez Signed-off-by: Jens Wiklander --- Documentation/ioctl/ioctl-number.txt | 1 + MAINTAINERS | 6 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/tee/Kconfig | 8 + drivers/tee/Makefile | 3 + drivers/tee/tee.c | 873 +++++++++++++++++++++++++++++++++++ drivers/tee/tee_private.h | 80 ++++ drivers/tee/tee_shm.c | 324 +++++++++++++ drivers/tee/tee_shm_pool.c | 133 ++++++ include/linux/tee_drv.h | 299 ++++++++++++ include/uapi/linux/tee.h | 383 +++++++++++++++ 12 files changed, 2113 insertions(+) create mode 100644 drivers/tee/Kconfig create mode 100644 drivers/tee/Makefile create mode 100644 drivers/tee/tee.c create mode 100644 drivers/tee/tee_private.h create mode 100644 drivers/tee/tee_shm.c create mode 100644 drivers/tee/tee_shm_pool.c create mode 100644 include/linux/tee_drv.h create mode 100644 include/uapi/linux/tee.h diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 91261a3..b5ce7b6 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -307,6 +307,7 @@ Code Seq#(hex) Include File Comments 0xA3 80-8F Port ACL in development: 0xA3 90-9F linux/dtlk.h +0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem 0xAA 00-3F linux/uapi/linux/userfaultfd.h 0xAB 00-1F linux/nbd.h 0xAC 00-1F linux/raw.h diff --git a/MAINTAINERS b/MAINTAINERS index 30aca4a..e3dfc81e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9566,6 +9566,12 @@ F: Documentation/trace/stm.txt F: drivers/hwtracing/stm/ F: include/linux/stm.h F: include/uapi/linux/stm.h +TEE SUBSYSTEM +M: Jens Wiklander +S: Maintained +F: include/linux/tee_drv.h +F: include/uapi/linux/tee.h +F: drivers/tee/ THUNDERBOLT DRIVER M: Andreas Noever diff --git a/drivers/Kconfig b/drivers/Kconfig index d2ac339..63baceb 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -198,4 +198,6 @@ source "drivers/hwtracing/intel_th/Kconfig" source "drivers/fpga/Kconfig" +source "drivers/tee/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 8f5d076..231b409 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -172,3 +172,4 @@ obj-$(CONFIG_STM) += hwtracing/stm/ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_NVMEM) += nvmem/ obj-$(CONFIG_FPGA) += fpga/ +obj-$(CONFIG_TEE) += tee/ diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig new file mode 100644 index 0000000..64a8cd7 --- /dev/null +++ b/drivers/tee/Kconfig @@ -0,0 +1,8 @@ +# Generic Trusted Execution Environment Configuration +config TEE + bool "Trusted Execution Environment support" + default n + select DMA_SHARED_BUFFER + help + This implements a generic interface towards a Trusted Execution + Environment (TEE). diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile new file mode 100644 index 0000000..60d2dab --- /dev/null +++ b/drivers/tee/Makefile @@ -0,0 +1,3 @@ +obj-y += tee.o +obj-y += tee_shm.o +obj-y += tee_shm_pool.o diff --git a/drivers/tee/tee.c b/drivers/tee/tee.c new file mode 100644 index 0000000..b8a1c76 --- /dev/null +++ b/drivers/tee/tee.c @@ -0,0 +1,873 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include "tee_private.h" + +#define TEE_NUM_DEVICES 32 + +#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x)) + +/* + * Unprivileged devices in the in the lower half range and privileged + * devices in the upper half range. + */ +static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES); +static DEFINE_SPINLOCK(driver_lock); + +static struct class *tee_class; +static dev_t tee_devt; + +static int tee_open(struct inode *inode, struct file *filp) +{ + int rc; + struct tee_device *teedev; + struct tee_context *ctx; + + teedev = container_of(inode->i_cdev, struct tee_device, cdev); + if (!tee_device_get(teedev)) + return -EINVAL; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + rc = -ENOMEM; + goto err; + } + + ctx->teedev = teedev; + filp->private_data = ctx; + rc = teedev->desc->ops->open(ctx); + if (rc) + goto err; + + return 0; +err: + kfree(ctx); + tee_device_put(teedev); + return rc; +} + +static int tee_release(struct inode *inode, struct file *filp) +{ + struct tee_context *ctx = filp->private_data; + struct tee_device *teedev = ctx->teedev; + + ctx->teedev->desc->ops->release(ctx); + kfree(ctx); + tee_device_put(teedev); + return 0; +} + +static int tee_ioctl_version(struct tee_context *ctx, + struct tee_ioctl_version_data __user *uvers) +{ + struct tee_ioctl_version_data vers; + + ctx->teedev->desc->ops->get_version(ctx->teedev, &vers); + if (copy_to_user(uvers, &vers, sizeof(vers))) + return -EFAULT; + return 0; +} + +static int tee_ioctl_shm_alloc(struct tee_context *ctx, + struct tee_ioctl_shm_alloc_data __user *udata) +{ + long ret; + struct tee_ioctl_shm_alloc_data data; + struct tee_shm *shm; + + if (copy_from_user(&data, udata, sizeof(data))) + return -EFAULT; + + /* Currently no input flags are supported */ + if (data.flags) + return -EINVAL; + + data.fd = -1; + + shm = tee_shm_alloc(ctx->teedev, data.size, + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + data.flags = shm->flags; + data.size = shm->size; + data.fd = tee_shm_get_fd(shm); + if (data.fd < 0) { + ret = data.fd; + goto err; + } + + if (copy_to_user(udata, &data, sizeof(data))) { + ret = -EFAULT; + goto err; + } + /* + * When user space closes the file descriptor the shared memory + * should be freed + */ + tee_shm_put(shm); + return 0; +err: + if (data.fd >= 0) + tee_shm_put_fd(data.fd); + tee_shm_free(shm); + return ret; +} + +static int params_from_user(struct tee_param *params, size_t num_params, + struct tee_ioctl_param __user *uparams) +{ + size_t n; + + for (n = 0; n < num_params; n++) { + struct tee_shm *shm; + struct tee_ioctl_param ip; + + if (copy_from_user(&ip, uparams + n, sizeof(ip))) + return -EFAULT; + + /* All unused attribute bits has to be zero */ + if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK) + return -EINVAL; + + params[n].attr = ip.attr; + switch (ip.attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + params[n].u.value.a = ip.u.value.a; + params[n].u.value.b = ip.u.value.b; + params[n].u.value.c = ip.u.value.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + /* + * If we fail to get a pointer to a shared memory + * object (and increase the ref count) from a file + * descriptor we return an error. All pointers that + * has been added in params have an increased ref + * count. It's the callers responibility to do + * tee_shm_put() on all resolved pointers. + */ + shm = tee_shm_get_from_fd(ip.u.memref.shm_fd); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + params[n].u.memref.shm_offs = ip.u.memref.shm_offs; + params[n].u.memref.size = ip.u.memref.size; + params[n].u.memref.shm = shm; + break; + default: + /* Unknown attribute */ + return -EINVAL; + } + } + return 0; +} + +static int params_to_user(struct tee_ioctl_param __user *uparams, + size_t num_params, struct tee_param *params) +{ + size_t n; + + for (n = 0; n < num_params; n++) { + struct tee_ioctl_param __user *up = uparams + n; + struct tee_param *p = params + n; + + switch (p->attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + if (put_user(p->u.value.a, &up->u.value.a) || + put_user(p->u.value.b, &up->u.value.b) || + put_user(p->u.value.c, &up->u.value.c)) + return -EFAULT; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + if (put_user((u64)p->u.memref.size, &up->u.memref.size)) + return -EFAULT; + default: + break; + } + } + return 0; +} + +static bool param_is_memref(struct tee_param *param) +{ + switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + return true; + default: + return false; + } +} + +static int tee_ioctl_open_session(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + int rc; + size_t n; + struct tee_ioctl_buf_data buf; + struct tee_ioctl_open_session_arg __user *uarg; + struct tee_ioctl_open_session_arg arg; + struct tee_ioctl_param __user *uparams = NULL; + struct tee_param *params = NULL; + bool have_session = false; + + if (!ctx->teedev->desc->ops->open_session) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_ioctl_open_session_arg)) + return -EINVAL; + + uarg = (struct tee_ioctl_open_session_arg __user *)(unsigned long) + buf.buf_ptr; + rc = copy_from_user(&arg, uarg, sizeof(arg)); + if (rc) + return rc; + + if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) + return -EINVAL; + + if (arg.num_params) { + params = kcalloc(arg.num_params, sizeof(struct tee_param), + GFP_KERNEL); + if (!params) + return -ENOMEM; + uparams = (struct tee_ioctl_param __user *)(uarg + 1); + rc = params_from_user(params, arg.num_params, uparams); + if (rc) + goto out; + } + + rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params); + if (rc) + goto out; + have_session = true; + + if (put_user(arg.session, &uarg->session) || + put_user(arg.ret, &uarg->ret) || + put_user(arg.ret_origin, &uarg->ret_origin)) { + rc = -EFAULT; + goto out; + } + rc = params_to_user(uparams, arg.num_params, params); +out: + /* + * If we've succeeded to open the session but failed to communicate + * it back to user space, close the session again to avoid leakage. + */ + if (rc && have_session && ctx->teedev->desc->ops->close_session) + ctx->teedev->desc->ops->close_session(ctx, arg.session); + + if (params) { + /* Decrease ref count for all valid shared memory pointers */ + for (n = 0; n < arg.num_params; n++) + if (param_is_memref(params + n) && + params[n].u.memref.shm) + tee_shm_put(params[n].u.memref.shm); + kfree(params); + } + + return rc; +} + +static int tee_ioctl_invoke(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + int rc; + size_t n; + struct tee_ioctl_buf_data buf; + struct tee_ioctl_invoke_arg __user *uarg; + struct tee_ioctl_invoke_arg arg; + struct tee_ioctl_param __user *uparams = NULL; + struct tee_param *params = NULL; + + if (!ctx->teedev->desc->ops->invoke_func) + return -EINVAL; + + rc = copy_from_user(&buf, ubuf, sizeof(buf)); + if (rc) + return rc; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_ioctl_invoke_arg)) + return -EINVAL; + + uarg = (struct tee_ioctl_invoke_arg __user *)(unsigned long)buf.buf_ptr; + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) + return -EINVAL; + + if (arg.num_params) { + params = kcalloc(arg.num_params, sizeof(struct tee_param), + GFP_KERNEL); + if (!params) + return -ENOMEM; + uparams = (struct tee_ioctl_param __user *)(uarg + 1); + rc = params_from_user(params, arg.num_params, uparams); + if (rc) + goto out; + } + + rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params); + if (rc) + goto out; + + if (put_user(arg.ret, &uarg->ret) || + put_user(arg.ret_origin, &uarg->ret_origin)) { + rc = -EFAULT; + goto out; + } + rc = params_to_user(uparams, arg.num_params, params); +out: + if (params) { + /* Decrease ref count for all valid shared memory pointers */ + for (n = 0; n < arg.num_params; n++) + if (param_is_memref(params + n) && + params[n].u.memref.shm) + tee_shm_put(params[n].u.memref.shm); + kfree(params); + } + return rc; +} + + +static int tee_ioctl_cancel(struct tee_context *ctx, + struct tee_ioctl_cancel_arg __user *uarg) +{ + struct tee_ioctl_cancel_arg arg; + + if (!ctx->teedev->desc->ops->cancel_req) + return -EINVAL; + + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + return ctx->teedev->desc->ops->cancel_req(ctx, arg.cancel_id, + arg.session); +} + +static int tee_ioctl_close_session(struct tee_context *ctx, + struct tee_ioctl_close_session_arg __user *uarg) +{ + struct tee_ioctl_close_session_arg arg; + + if (!ctx->teedev->desc->ops->close_session) + return -EINVAL; + + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + return ctx->teedev->desc->ops->close_session(ctx, arg.session); +} + +static int params_to_supp(struct tee_ioctl_param __user *uparams, + size_t num_params, struct tee_param *params) +{ + int rc = 0; + size_t n; + int *fds = kmalloc_array(num_params, sizeof(int), GFP_KERNEL); + + if (!fds) + return -ENOMEM; + for (n = 0; n < num_params; n++) + fds[n] = -1; + + for (n = 0; n < num_params; n++) { + struct tee_ioctl_param ip; + struct tee_param *p = params + n; + + ip.attr = p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK; + switch (p->attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + ip.u.value.a = p->u.value.a; + ip.u.value.b = p->u.value.b; + ip.u.value.c = p->u.value.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + ip.u.memref.size = p->u.memref.size; + if (!p->u.memref.shm) { + ip.u.memref.shm_offs = 0; + ip.u.memref.shm_fd = -1; + break; + } + ip.u.memref.shm_offs = p->u.memref.shm_offs; + /* + * This tee_shm_get_fd() is supposed to be matched + * by a close(2) from tee-supplicant. + */ + fds[n] = tee_shm_get_fd(p->u.memref.shm); + if (fds[n] < 0) { + rc = fds[n]; + goto out; + } + ip.u.memref.shm_fd = fds[n]; + break; + default: + memset(&ip.u, 0, sizeof(ip.u)); + break; + } + + if (copy_to_user(uparams + n, &ip, sizeof(ip))) { + rc = -EFAULT; + goto out; + } + } +out: + if (rc) { + for (n = 0; n < num_params; n++) + if (fds[n] >= 0) + tee_shm_put_fd(fds[n]); + } + kfree(fds); + return rc; +} + +static int tee_ioctl_supp_recv(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + int rc; + struct tee_ioctl_buf_data buf; + struct tee_iocl_supp_recv_arg __user *uarg; + struct tee_param *params; + struct tee_ioctl_param __user *uparams; + u32 num_params; + u32 func; + + if (!ctx->teedev->desc->ops->supp_recv) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_iocl_supp_recv_arg)) + return -EINVAL; + + uarg = (struct tee_iocl_supp_recv_arg __user *)(unsigned long) + buf.buf_ptr; + if (get_user(num_params, &uarg->num_params)) + return -EFAULT; + + if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) != buf.buf_len) + return -EINVAL; + + params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); + if (!params) + return -ENOMEM; + + rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params); + if (rc) + goto out; + + if (put_user(func, &uarg->func) || + put_user(num_params, &uarg->num_params)) { + rc = -EFAULT; + goto out; + } + + uparams = (struct tee_ioctl_param __user *)(uarg + 1); + rc = params_to_supp(uparams, num_params, params); +out: + kfree(params); + return rc; +} + +static int params_from_supp(struct tee_param *params, + size_t num_params, struct tee_ioctl_param __user *uparams) +{ + size_t n; + + for (n = 0; n < num_params; n++) { + struct tee_param *p = params + n; + struct tee_ioctl_param ip; + + if (copy_from_user(&ip, uparams + n, sizeof(ip))) + return -EFAULT; + + /* All unused attribute bits has to be zero */ + if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK) + return -EINVAL; + + p->attr = ip.attr; + switch (ip.attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + /* Only out and in/out values can be updated */ + p->u.value.a = ip.u.value.a; + p->u.value.b = ip.u.value.b; + p->u.value.c = ip.u.value.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + /* + * Only the size of the memref can be updated. + * Since we don't have access to the original + * parameters here, only store the supplied size. + * The driver will copy the updated size into the + * original parameters. + */ + p->u.memref.shm = NULL; + p->u.memref.shm_offs = 0; + p->u.memref.size = ip.u.memref.size; + break; + default: + memset(&p->u, 0, sizeof(p->u)); + break; + } + } + return 0; +} + +static int tee_ioctl_supp_send(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + long rc; + struct tee_ioctl_buf_data buf; + struct tee_iocl_supp_send_arg __user *uarg; + struct tee_param *params; + struct tee_ioctl_param __user *uparams; + u32 num_params; + u32 ret; + + /* Not valid for this driver */ + if (!ctx->teedev->desc->ops->supp_send) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_iocl_supp_send_arg)) + return -EINVAL; + + uarg = (struct tee_iocl_supp_send_arg __user *)(unsigned long) + buf.buf_ptr; + if (get_user(ret, &uarg->ret) || + get_user(num_params, &uarg->num_params)) + return -EFAULT; + + if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) > buf.buf_len) + return -EINVAL; + + params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); + if (!params) + return -ENOMEM; + + uparams = (struct tee_ioctl_param __user *)(uarg + 1); + rc = params_from_supp(params, num_params, uparams); + if (rc) + goto out; + + rc = ctx->teedev->desc->ops->supp_send(ctx, ret, num_params, params); +out: + kfree(params); + return rc; +} + + +static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct tee_context *ctx = filp->private_data; + void __user *uarg = (void __user *)arg; + + switch (cmd) { + case TEE_IOC_VERSION: + return tee_ioctl_version(ctx, uarg); + case TEE_IOC_SHM_ALLOC: + return tee_ioctl_shm_alloc(ctx, uarg); + case TEE_IOC_OPEN_SESSION: + return tee_ioctl_open_session(ctx, uarg); + case TEE_IOC_INVOKE: + return tee_ioctl_invoke(ctx, uarg); + case TEE_IOC_CANCEL: + return tee_ioctl_cancel(ctx, uarg); + case TEE_IOC_CLOSE_SESSION: + return tee_ioctl_close_session(ctx, uarg); + case TEE_IOC_SUPPL_RECV: + return tee_ioctl_supp_recv(ctx, uarg); + case TEE_IOC_SUPPL_SEND: + return tee_ioctl_supp_send(ctx, uarg); + default: + return -EINVAL; + } +} + +static const struct file_operations tee_fops = { + .open = tee_open, + .release = tee_release, + .unlocked_ioctl = tee_ioctl, + .compat_ioctl = tee_ioctl, +}; + +static void tee_release_device(struct device *dev) +{ + struct tee_device *teedev = container_of(dev, struct tee_device, dev); + + spin_lock(&driver_lock); + clear_bit(teedev->id, dev_mask); + spin_unlock(&driver_lock); + mutex_destroy(&teedev->mutex); + kfree(teedev); +} + +struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, + struct device *dev, struct tee_shm_pool *pool, + void *driver_data) +{ + struct tee_device *teedev; + void *ret; + int rc; + int offs = 0; + + if (!teedesc || !teedesc->name || !teedesc->ops || + !teedesc->ops->get_version || !teedesc->ops->open || + !teedesc->ops->release || !dev || !pool) + return ERR_PTR(-EINVAL); + + teedev = kzalloc(sizeof(*teedev), GFP_KERNEL); + if (!teedev) { + ret = ERR_PTR(-ENOMEM); + goto err; + } + + if (teedesc->flags & TEE_DESC_PRIVILEGED) + offs = TEE_NUM_DEVICES / 2; + + spin_lock(&driver_lock); + teedev->id = find_next_zero_bit(dev_mask, TEE_NUM_DEVICES, offs); + if (teedev->id < TEE_NUM_DEVICES) + set_bit(teedev->id, dev_mask); + spin_unlock(&driver_lock); + + if (teedev->id >= TEE_NUM_DEVICES) { + ret = ERR_PTR(-ENOMEM); + goto err; + } + + snprintf(teedev->name, sizeof(teedev->name), "tee%s%d", + teedesc->flags & TEE_DESC_PRIVILEGED ? "priv" : "", + teedev->id - offs); + + teedev->dev.class = tee_class; + teedev->dev.release = tee_release_device; + teedev->dev.parent = dev; + teedev->dev.devt = MKDEV(MAJOR(tee_devt), teedev->id); + + rc = dev_set_name(&teedev->dev, "%s", teedev->name); + if (rc) { + ret = ERR_PTR(rc); + goto err; + } + + cdev_init(&teedev->cdev, &tee_fops); + teedev->cdev.owner = teedesc->owner; + teedev->cdev.kobj.parent = &teedev->dev.kobj; + + dev_set_drvdata(&teedev->dev, driver_data); + device_initialize(&teedev->dev); + + /* 1 as tee_device_unregister() does one final tee_device_put() */ + teedev->num_users = 1; + init_completion(&teedev->c_no_users); + mutex_init(&teedev->mutex); + + teedev->desc = teedesc; + teedev->pool = pool; + INIT_LIST_HEAD(&teedev->list_shm); + + return teedev; +err: + dev_err(dev, "could not register %s driver\n", + teedesc->flags & TEE_DESC_PRIVILEGED ? "privileged" : "client"); + if (teedev && teedev->id < TEE_NUM_DEVICES) { + spin_lock(&driver_lock); + clear_bit(teedev->id, dev_mask); + spin_unlock(&driver_lock); + } + kfree(teedev); + return ret; +} +EXPORT_SYMBOL_GPL(tee_device_alloc); + +static ssize_t implementation_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tee_device *teedev = container_of(dev, struct tee_device, dev); + struct tee_ioctl_version_data vers; + + teedev->desc->ops->get_version(teedev, &vers); + return scnprintf(buf, PAGE_SIZE, "%d\n", vers.impl_id); +} +static DEVICE_ATTR_RO(implementation_id); + +static struct attribute *tee_dev_attrs[] = { + &dev_attr_implementation_id.attr, + NULL +}; + +static const struct attribute_group tee_dev_group = { + .attrs = tee_dev_attrs, +}; + +int tee_device_register(struct tee_device *teedev) +{ + int rc; + + /* + * If the teedev already is registered, don't do it again. It's + * obviously an error to try to register twice, but if we return + * an error we'll force the driver to remove the teedev. + */ + if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { + dev_err(&teedev->dev, "attempt to register twice\n"); + return 0; + } + + rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1); + if (rc) { + dev_err(&teedev->dev, + "unable to cdev_add() %s, major %d, minor %d, err=%d\n", + teedev->name, MAJOR(teedev->dev.devt), + MINOR(teedev->dev.devt), rc); + return rc; + } + + rc = device_add(&teedev->dev); + if (rc) { + dev_err(&teedev->dev, + "unable to device_add() %s, major %d, minor %d, err=%d\n", + teedev->name, MAJOR(teedev->dev.devt), + MINOR(teedev->dev.devt), rc); + goto err_device_add; + } + + rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group); + if (rc) { + dev_err(&teedev->dev, + "failed to create sysfs attributes, err=%d\n", rc); + goto err_sysfs_create_group; + } + + teedev->flags |= TEE_DEVICE_FLAG_REGISTERED; + return 0; + +err_sysfs_create_group: + device_del(&teedev->dev); +err_device_add: + cdev_del(&teedev->cdev); + return rc; + +} +EXPORT_SYMBOL_GPL(tee_device_register); + +void tee_device_put(struct tee_device *teedev) +{ + mutex_lock(&teedev->mutex); + /* Shouldn't put in this state */ + if (!WARN_ON(!teedev->desc)) { + teedev->num_users--; + if (!teedev->num_users) { + teedev->desc = NULL; + complete(&teedev->c_no_users); + } + } + mutex_unlock(&teedev->mutex); +} + +bool tee_device_get(struct tee_device *teedev) +{ + mutex_lock(&teedev->mutex); + if (!teedev->desc) { + mutex_unlock(&teedev->mutex); + return false; + } + teedev->num_users++; + mutex_unlock(&teedev->mutex); + return true; +} + +void tee_device_unregister(struct tee_device *teedev) +{ + if (!teedev) + return; + + if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { + sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group); + cdev_del(&teedev->cdev); + device_del(&teedev->dev); + } + + tee_device_put(teedev); + wait_for_completion(&teedev->c_no_users); + + /* + * No need to take a mutex any longer now since teedev->desc was + * set to NULL before teedev->c_no_users was completed. + */ + + teedev->pool = NULL; + + put_device(&teedev->dev); +} +EXPORT_SYMBOL_GPL(tee_device_unregister); + +void *tee_get_drvdata(struct tee_device *teedev) +{ + return dev_get_drvdata(&teedev->dev); +} +EXPORT_SYMBOL_GPL(tee_get_drvdata); + +static int __init tee_init(void) +{ + int rc; + + tee_class = class_create(THIS_MODULE, "tee"); + if (IS_ERR(tee_class)) { + pr_err("couldn't create class\n"); + return PTR_ERR(tee_class); + } + + rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee"); + if (rc < 0) { + pr_err("failed to allocate char dev region\n"); + class_destroy(tee_class); + tee_class = NULL; + } + + return rc; +} + +subsys_initcall(tee_init); diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h new file mode 100644 index 0000000..d32ac54 --- /dev/null +++ b/drivers/tee/tee_private.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef TEE_PRIVATE_H +#define TEE_PRIVATE_H + +#include +#include +#include +#include +#include +#include + +struct tee_device; + +struct tee_shm { + struct list_head list_node; + struct tee_device *teedev; + phys_addr_t paddr; + void *kaddr; + size_t size; + struct dma_buf *dmabuf; + u32 flags; +}; + +struct tee_shm_pool_mgr; +struct tee_shm_pool_mgr_ops { + int (*alloc)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm, + size_t size); + void (*free)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm); +}; + +struct tee_shm_pool_mgr { + const struct tee_shm_pool_mgr_ops *ops; + void *private_data; +}; + +struct tee_shm_pool { + struct tee_shm_pool_mgr private_mgr; + struct tee_shm_pool_mgr dma_buf_mgr; + void (*destroy)(struct tee_shm_pool *pool); + void *private_data; +}; + +#define TEE_DEVICE_FLAG_REGISTERED 0x1 +#define TEE_MAX_DEV_NAME_LEN 32 + +struct tee_device { + char name[TEE_MAX_DEV_NAME_LEN]; + const struct tee_desc *desc; + int id; + unsigned flags; + + struct device dev; + struct cdev cdev; + + size_t num_users; + struct completion c_no_users; + struct mutex mutex; + + struct list_head list_shm; + struct tee_shm_pool *pool; +}; + +int tee_shm_init(void); + +bool tee_device_get(struct tee_device *teedev); +void tee_device_put(struct tee_device *teedev); + +#endif /*TEE_PRIVATE_H*/ diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c new file mode 100644 index 0000000..6732e77 --- /dev/null +++ b/drivers/tee/tee_shm.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include "tee_private.h" + +static void tee_shm_release(struct tee_shm *shm) +{ + struct tee_device *teedev = shm->teedev; + struct tee_shm_pool_mgr *poolm; + + mutex_lock(&teedev->mutex); + list_del(&shm->list_node); + mutex_unlock(&teedev->mutex); + + if (shm->flags & TEE_SHM_DMA_BUF) + poolm = &teedev->pool->dma_buf_mgr; + else + poolm = &teedev->pool->private_mgr; + + poolm->ops->free(poolm, shm); + kfree(shm); + + tee_device_put(teedev); +} + +static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment + *attach, enum dma_data_direction dir) +{ + return NULL; +} + +static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach, + struct sg_table *table, enum dma_data_direction dir) +{ +} + +static void tee_shm_op_release(struct dma_buf *dmabuf) +{ + struct tee_shm *shm = dmabuf->priv; + + tee_shm_release(shm); +} + +static void *tee_shm_op_kmap_atomic(struct dma_buf *dmabuf, + unsigned long pgnum) +{ + return NULL; +} + +static void *tee_shm_op_kmap(struct dma_buf *dmabuf, unsigned long pgnum) +{ + return NULL; +} + +static int tee_shm_op_mmap(struct dma_buf *dmabuf, + struct vm_area_struct *vma) +{ + struct tee_shm *shm = dmabuf->priv; + size_t size = vma->vm_end - vma->vm_start; + + return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT, + size, vma->vm_page_prot); +} + +static struct dma_buf_ops tee_shm_dma_buf_ops = { + .map_dma_buf = tee_shm_op_map_dma_buf, + .unmap_dma_buf = tee_shm_op_unmap_dma_buf, + .release = tee_shm_op_release, + .kmap_atomic = tee_shm_op_kmap_atomic, + .kmap = tee_shm_op_kmap, + .mmap = tee_shm_op_mmap, +}; + +struct tee_shm *tee_shm_alloc(struct tee_device *teedev, size_t size, + u32 flags) +{ + struct tee_shm_pool_mgr *poolm = NULL; + struct tee_shm *shm; + void *ret; + int rc; + + if (!(flags & TEE_SHM_MAPPED)) { + dev_err(teedev->dev.parent, + "only mapped allocations supported\n"); + return ERR_PTR(-EINVAL); + } + + if ((flags & ~(TEE_SHM_MAPPED|TEE_SHM_DMA_BUF))) { + dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags); + return ERR_PTR(-EINVAL); + } + + if (!tee_device_get(teedev)) + return ERR_PTR(-EINVAL); + + if (!teedev->pool) { + /* teedev has been detached from driver */ + ret = ERR_PTR(-EINVAL); + goto err; + } + + shm = kzalloc(sizeof(struct tee_shm), GFP_KERNEL); + if (!shm) { + ret = ERR_PTR(-ENOMEM); + goto err; + } + + shm->flags = flags; + shm->teedev = teedev; + if (flags & TEE_SHM_DMA_BUF) + poolm = &teedev->pool->dma_buf_mgr; + else + poolm = &teedev->pool->private_mgr; + + rc = poolm->ops->alloc(poolm, shm, size); + if (rc) { + ret = ERR_PTR(rc); + goto err; + } + + mutex_lock(&teedev->mutex); + list_add_tail(&shm->list_node, &teedev->list_shm); + mutex_unlock(&teedev->mutex); + + if (flags & TEE_SHM_DMA_BUF) { + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &tee_shm_dma_buf_ops; + exp_info.size = shm->size; + exp_info.flags = O_RDWR; + exp_info.priv = shm; + + shm->dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(shm->dmabuf)) { + ret = ERR_CAST(shm->dmabuf); + goto err; + } + } + + return shm; +err: + if (poolm && shm && shm->kaddr) + poolm->ops->free(poolm, shm); + kfree(shm); + tee_device_put(teedev); + return ret; +} +EXPORT_SYMBOL_GPL(tee_shm_alloc); + +int tee_shm_get_fd(struct tee_shm *shm) +{ + u32 req_flags = TEE_SHM_MAPPED | TEE_SHM_DMA_BUF; + int fd; + + if ((shm->flags & req_flags) != req_flags) + return -EINVAL; + + fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC); + if (fd >= 0) + get_dma_buf(shm->dmabuf); + return fd; +} +EXPORT_SYMBOL_GPL(tee_shm_get_fd); + +int tee_shm_put_fd(int fd) +{ + return __close_fd(current->files, fd); +} +EXPORT_SYMBOL_GPL(tee_shm_put_fd); + +void tee_shm_free(struct tee_shm *shm) +{ + + /* + * dma_buf_put() decreases the dmabuf reference counter and will + * call tee_shm_release() when the last reference is gone. + * + * In the case of driver private memory we call tee_shm_release + * directly instead as it doesn't have a reference counter. + */ + if (shm->flags & TEE_SHM_DMA_BUF) + dma_buf_put(shm->dmabuf); + else + tee_shm_release(shm); +} +EXPORT_SYMBOL_GPL(tee_shm_free); + +static bool cmp_key_va(struct tee_shm *shm, uintptr_t va) +{ + uintptr_t shm_va = (uintptr_t)shm->kaddr; + + return (va >= shm_va) && (va < (shm_va + shm->size)); +} + +static bool cmp_key_pa(struct tee_shm *shm, uintptr_t pa) +{ + return (pa >= shm->paddr) && (pa < (shm->paddr + shm->size)); +} + +static struct tee_shm *tee_shm_find_by_key(struct tee_device *teedev, u32 flags, + bool (*cmp)(struct tee_shm *shm, uintptr_t key), + uintptr_t key) +{ + struct tee_shm *ret = NULL; + struct tee_shm *shm; + + mutex_lock(&teedev->mutex); + list_for_each_entry(shm, &teedev->list_shm, list_node) { + if (cmp(shm, key)) { + ret = shm; + break; + } + } + mutex_unlock(&teedev->mutex); + + return ret; +} + +struct tee_shm *tee_shm_find_by_va(struct tee_device *teedev, u32 flags, + void *va) +{ + return tee_shm_find_by_key(teedev, flags, cmp_key_va, (uintptr_t)va); +} +EXPORT_SYMBOL_GPL(tee_shm_find_by_va); + +struct tee_shm *tee_shm_find_by_pa(struct tee_device *teedev, u32 flags, + phys_addr_t pa) +{ + return tee_shm_find_by_key(teedev, flags, cmp_key_pa, pa); +} +EXPORT_SYMBOL_GPL(tee_shm_find_by_pa); + +int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa) +{ + /* Check that we're in the range of the shm */ + if ((char *)va < (char *)shm->kaddr) + return -EINVAL; + if ((char *)va >= ((char *)shm->kaddr + shm->size)) + return -EINVAL; + + return tee_shm_get_pa( + shm, (unsigned long)va - (unsigned long)shm->kaddr, pa); +} +EXPORT_SYMBOL_GPL(tee_shm_va2pa); + +int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va) +{ + /* Check that we're in the range of the shm */ + if (pa < shm->paddr) + return -EINVAL; + if (pa >= (shm->paddr + shm->size)) + return -EINVAL; + + if (va) { + void *v = tee_shm_get_va(shm, pa - shm->paddr); + + if (IS_ERR(v)) + return PTR_ERR(v); + *va = v; + } + return 0; +} +EXPORT_SYMBOL_GPL(tee_shm_pa2va); + +void *tee_shm_get_va(struct tee_shm *shm, size_t offs) +{ + if (offs >= shm->size) + return ERR_PTR(-EINVAL); + return (char *)shm->kaddr + offs; +} +EXPORT_SYMBOL_GPL(tee_shm_get_va); + +int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa) +{ + if (offs >= shm->size) + return -EINVAL; + if (pa) + *pa = shm->paddr + offs; + return 0; +} +EXPORT_SYMBOL_GPL(tee_shm_get_pa); + +static bool is_shm_dma_buf(struct dma_buf *dmabuf) +{ + return dmabuf->ops == &tee_shm_dma_buf_ops; +} + +struct tee_shm *tee_shm_get_from_fd(int fd) +{ + struct dma_buf *dmabuf = dma_buf_get(fd); + + if (IS_ERR(dmabuf)) + return ERR_CAST(dmabuf); + + if (!is_shm_dma_buf(dmabuf)) { + dma_buf_put(dmabuf); + return ERR_PTR(-EINVAL); + } + return dmabuf->priv; +} +EXPORT_SYMBOL_GPL(tee_shm_get_from_fd); + +void tee_shm_put(struct tee_shm *shm) +{ + if (shm->flags & TEE_SHM_DMA_BUF) + dma_buf_put(shm->dmabuf); +} +EXPORT_SYMBOL_GPL(tee_shm_put); diff --git a/drivers/tee/tee_shm_pool.c b/drivers/tee/tee_shm_pool.c new file mode 100644 index 0000000..2ef22bc --- /dev/null +++ b/drivers/tee/tee_shm_pool.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include "tee_private.h" + +static int pool_op_gen_alloc(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm, size_t size) +{ + unsigned long va; + struct gen_pool *genpool = poolm->private_data; + size_t s = roundup(size, 1 << genpool->min_alloc_order); + + va = gen_pool_alloc(genpool, s); + if (!va) + return -ENOMEM; + shm->kaddr = (void *)va; + shm->paddr = gen_pool_virt_to_phys(genpool, va); + shm->size = s; + return 0; +} + +static void pool_op_gen_free(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm) +{ + gen_pool_free(poolm->private_data, (unsigned long)shm->kaddr, + shm->size); + shm->kaddr = NULL; +} + +static const struct tee_shm_pool_mgr_ops pool_ops_generic = { + .alloc = pool_op_gen_alloc, + .free = pool_op_gen_free, +}; + +static void pool_res_mem_destroy(struct tee_shm_pool *pool) +{ + gen_pool_destroy(pool->private_mgr.private_data); + gen_pool_destroy(pool->dma_buf_mgr.private_data); +} + +static int pool_res_mem_mgr_init(struct tee_shm_pool_mgr *mgr, + struct tee_shm_pool_mem_info *info, int min_alloc_order) +{ + size_t page_mask = PAGE_SIZE - 1; + struct gen_pool *genpool = NULL; + int rc; + + /* + * Start and end must be page aligned + */ + if ((info->vaddr & page_mask) || (info->paddr & page_mask) || + (info->size & page_mask)) + return -EINVAL; + + genpool = gen_pool_create(min_alloc_order, -1); + if (!genpool) + return -ENOMEM; + + gen_pool_set_algo(genpool, gen_pool_best_fit, NULL); + rc = gen_pool_add_virt(genpool, info->vaddr, info->paddr, info->size, + -1); + if (rc) { + gen_pool_destroy(genpool); + return rc; + } + + mgr->private_data = genpool; + mgr->ops = &pool_ops_generic; + return 0; +} + +struct tee_shm_pool *tee_shm_pool_alloc_res_mem(struct device *dev, + struct tee_shm_pool_mem_info *priv_info, + struct tee_shm_pool_mem_info *dmabuf_info) +{ + struct tee_shm_pool *pool = NULL; + int ret; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) { + ret = -ENOMEM; + goto err; + } + + /* + * Create the pool for driver private shared memory + */ + ret = pool_res_mem_mgr_init(&pool->private_mgr, priv_info, + 3 /* 8 byte aligned */); + if (ret) + goto err; + + /* + * Create the pool for dma_buf shared memory + */ + ret = pool_res_mem_mgr_init(&pool->dma_buf_mgr, dmabuf_info, + PAGE_SHIFT); + if (ret) + goto err; + + pool->destroy = pool_res_mem_destroy; + return pool; +err: + if (ret == -ENOMEM) + dev_err(dev, "can't allocate memory for res_mem shared memory pool\n"); + if (pool && pool->private_mgr.private_data) + gen_pool_destroy(pool->private_mgr.private_data); + kfree(pool); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem); + +void tee_shm_pool_free(struct tee_shm_pool *pool) +{ + pool->destroy(pool); + kfree(pool); +} +EXPORT_SYMBOL_GPL(tee_shm_pool_free); diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h new file mode 100644 index 0000000..06cffa6 --- /dev/null +++ b/include/linux/tee_drv.h @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __TEE_DRV_H +#define __TEE_DRV_H + +#include +#include +#include + +/* + * The file describes the API provided by the generic TEE driver to the + * specific TEE driver. + */ + +#define TEE_SHM_MAPPED 0x1 /* Memory mapped by the kernel */ +#define TEE_SHM_DMA_BUF 0x2 /* Memory with dma-buf handle */ + +struct tee_device; +struct tee_shm; +struct tee_shm_pool; + +/** + * struct tee_context - driver specific context on file pointer data + * @teedev: pointer to this drivers struct tee_device + * @data: driver specific context data, managed by the driver + */ +struct tee_context { + struct tee_device *teedev; + void *data; +}; + +struct tee_param_memref { + size_t shm_offs; + size_t size; + struct tee_shm *shm; +}; + +struct tee_param_value { + u64 a; + u64 b; + u64 c; +}; + +struct tee_param { + u64 attr; + union { + struct tee_param_memref memref; + struct tee_param_value value; + } u; +}; + +/** + * struct tee_driver_ops - driver operations vtable + * @get_version: returns version of driver + * @open: called when the device file is opened + * @release: release this open file + */ +struct tee_driver_ops { + void (*get_version)(struct tee_device *teedev, + struct tee_ioctl_version_data *vers); + int (*open)(struct tee_context *ctx); + void (*release)(struct tee_context *ctx); + int (*open_session)(struct tee_context *ctx, + struct tee_ioctl_open_session_arg *arg, + struct tee_param *param); + int (*close_session)(struct tee_context *ctx, u32 session); + int (*invoke_func)(struct tee_context *ctx, + struct tee_ioctl_invoke_arg *arg, + struct tee_param *param); + int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session); + int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params, + struct tee_param *param); + int (*supp_send)(struct tee_context *ctx, u32 ret, u32 num_params, + struct tee_param *param); +}; + +/** + * struct tee_desc - Describes the TEE driver to the subsystem + * @name: name of driver + * @ops: driver operations vtable + * @owner: module providing the driver + * @flags: Extra properties of driver, defined by TEE_DESC_* below + */ +#define TEE_DESC_PRIVILEGED 0x1 +struct tee_desc { + const char *name; + const struct tee_driver_ops *ops; + struct module *owner; + u32 flags; +}; + + +/** + * tee_device_alloc() - Allocate a new struct tee_device instance + * @teedesc: Descriptor for this driver + * @dev: Parent device for this device + * @pool: Shared memory pool, NULL if not used + * @driver_data: Private driver data for this device + * + * Allocates a new struct tee_device instance. The device is + * removed by tee_device_unregister(). + * + * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure + */ +struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, + struct device *dev, struct tee_shm_pool *pool, + void *driver_data); + +/** + * tee_device_register() - Registers a TEE device + * @teedev: Device to register + * + * tee_device_unregister() need to be called to remove the @teedev if + * this function fails. + * + * @returns < 0 on failure + */ +int tee_device_register(struct tee_device *teedev); + +/** + * tee_device_unregister() - Removes a TEE device + * @teedev: Device to unregister + * + * This function should be called to remove the @teedev even if + * tee_device_register() hasn't been called yet. Does nothing if + * @teedev is NULL. + */ +void tee_device_unregister(struct tee_device *teedev); + +/** + * struct tee_shm_pool_mem_info - holds information needed to create a shared memory pool + * @vaddr: Virtual address of start of pool + * @paddr: Physical address of start of pool + * @size: Size in bytes of the pool + */ +struct tee_shm_pool_mem_info { + unsigned long vaddr; + unsigned long paddr; + size_t size; +}; + +/** + * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved memory range + * @dev: Device allocating the pool + * @priv_info: Information for driver private shared memory pool + * @dmabuf_info: Information for dma-buf shared memory pool + * + * Start and end of pools will must be page aligned. + * + * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied + * in @dmabuf, others will use the range provided by @priv. + * + * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure. + */ +struct tee_shm_pool *tee_shm_pool_alloc_res_mem(struct device *dev, + struct tee_shm_pool_mem_info *priv_info, + struct tee_shm_pool_mem_info *dmabuf_info); + +/** + * tee_shm_pool_free() - Free a shared memory pool + * @pool: The shared memory pool to free + * + * The must be no remaining shared memory allocated from this pool when + * this function is called. + */ +void tee_shm_pool_free(struct tee_shm_pool *pool); + +/** + * tee_get_drvdata() - Return driver_data pointer + * @returns the driver_data pointer supplied to tee_register(). + */ +void *tee_get_drvdata(struct tee_device *teedev); + +/** + * tee_shm_alloc() - Allocate shared memory + * @teedev: Driver that allocates the shared memory + * @size: Requested size of shared memory + * @flags: Flags setting properties for the requested shared memory. + * + * Memory allocated as global shared memory is automatically freed when the + * TEE file pointer is closed. The @flags field uses the bits defined by + * TEE_SHM_* above. TEE_SHM_MAPPED must currently always be set. If + * TEE_SHM_DMA_BUF global shared memory will be allocated and associated + * with a dma-buf handle, else driver private memory. + * + * @returns a pointer to 'struct tee_shm' + */ +struct tee_shm *tee_shm_alloc(struct tee_device *teedev, size_t size, + u32 flags); + +/** + * tee_shm_free() - Free shared memory + * @shm: Handle to shared memory to free + */ +void tee_shm_free(struct tee_shm *shm); + +/** + * tee_shm_find_by_va() - Find a shared memory handle by a virtual address + * @teedev: The device that owns the shared memory + * @flags: Select which type of shared memory to locate, if + * TEE_SHM_DMA_BUF global shared memory else driver private + * shared memory. + * @va: Virtual address covered by the shared memory + * @returns a Handle to shared memory + */ +struct tee_shm *tee_shm_find_by_va(struct tee_device *teedev, u32 flags, + void *va); +/** + * tee_shm_find_by_pa() - Find a shared memory handle by a physical address + * @teedev: The device that owns the shared memory + * @flags: Select which type of shared memory to locate, if + * TEE_SHM_DMA_BUF global shared memory else driver private + * shared memory. + * @pa: Physical address covered by the shared memory + * @returns a Handle to shared memory + */ +struct tee_shm *tee_shm_find_by_pa(struct tee_device *teedev, u32 flags, + phys_addr_t pa); + +/** + * tee_shm_va2pa() - Get physical address of a virtual address + * @shm: Shared memory handle + * @va: Virtual address to tranlsate + * @pa: Returned physical address + * @returns 0 on success and < 0 on failure + */ +int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa); + +/** + * tee_shm_pa2va() - Get virtual address of a physical address + * @shm: Shared memory handle + * @pa: Physical address to tranlsate + * @va: Returned virtual address + * @returns 0 on success and < 0 on failure + */ +int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va); + +/** + * tee_shm_get_va() - Get virtual address of a shared memory plus an offset + * @shm: Shared memory handle + * @offs: Offset from start of this shared memory + * @returns virtual address of the shared memory + offs if offs is within + * the bounds of this shared memory, else an ERR_PTR + */ +void *tee_shm_get_va(struct tee_shm *shm, size_t offs); + +/** + * tee_shm_get_pa() - Get physical address of a shared memory plus an offset + * @shm: Shared memory handle + * @offs: Offset from start of this shared memory + * @pa: Physical address to return + * @returns 0 if offs is within the bounds of this shared memory, else an + * error code. + */ +int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa); + +/** + * tee_shm_get_from_fd() - Get a shared memory handle from a file descriptor + * @fd: A user space file descriptor + * + * This function increases the reference counter on the shared memory and + * returns a handle. + * @returns handle to shared memory + */ +struct tee_shm *tee_shm_get_from_fd(int fd); + +/** + * tee_shm_put() - Decrease reference count on a shared memory handle + * @shm: Shared memory handle + */ +void tee_shm_put(struct tee_shm *shm); + +/** + * tee_shm_get_fd() - Increase reference count and return file descriptor + * @shm: Shared memory handle + * @returns user space file descriptor to shared memory + */ +int tee_shm_get_fd(struct tee_shm *shm); + +/** + * tee_shm_put_fd() - Decrease reference count and close file descriptor + * @fd: File descriptor to close + * @returns < 0 on failure + */ +int tee_shm_put_fd(int fd); + +#endif /*__TEE_DRV_H*/ diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h new file mode 100644 index 0000000..319cc61 --- /dev/null +++ b/include/uapi/linux/tee.h @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __TEE_H +#define __TEE_H + +#include +#include + +/* + * This file describes the API provided by a TEE driver to user space. + * + * Each TEE driver defines a TEE specific protocol which is used for the + * data passed back and forth using TEE_IOC_CMD. + */ + + +/* Helpers to make the ioctl defines */ +#define TEE_IOC_MAGIC 0xa4 +#define TEE_IOC_BASE 0 + +/* Flags relating to shared memory */ +#define TEE_IOCTL_SHM_MAPPED 0x1 /* memory mapped in normal world */ +#define TEE_IOCTL_SHM_DMA_BUF 0x2 /* dma-buf handle on shared memory */ + +#define TEE_MAX_ARG_SIZE 1024 + +#define TEE_GEN_CAP_GP (1 << 0)/* Global Platform compliant TEE */ + +/* + * TEE Implementation ID + */ +#define TEE_IMPL_ID_OPTEE 1 + +/* + * OP-TEE specific capabilities + */ +#define TEE_OPTEE_CAP_TZ (1 << 0) + +/** + * struct tee_ioctl_version_data - TEE version + * @impl_id: [out] TEE implementation id + * @impl_caps: [out] Implementation specific capabilities + * @gen_caps: [out] Generic capabilities, defined by TEE_GEN_CAPS_* above + * + * Identifies the TEE implementaion, @impl_id is one of TEE_IMPL_ID_* above. + * @impl_caps is implementation specific, for example TEE_OPTEE_CAP_* + * is valid when @impl_id == TEE_IMPL_ID_OPTEE. + */ +struct tee_ioctl_version_data { + __u32 impl_id; + __u32 impl_caps; + __u32 gen_caps; +}; +/** + * TEE_IOC_VERSION - query version of TEE + * + * Takes a tee_version struct and returns with the TEE version data filled + * in. + */ +#define TEE_IOC_VERSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 0, \ + struct tee_ioctl_version_data) + +/** + * struct tee_ioctl_shm_alloc_data - Shared memory allocate argument + * @size: [in/out] Size of shared memory to allocate + * @flags: [in/out] Flags to/from allocation. + * @fd: [out] dma_buf file descriptor of the shared memory + * + * The flags field should currently be zero as input. Updated by the call + * with actual flags as defined by TEE_IOCTL_SHM_* above. + * This structure is used as argument for TEE_IOC_SHM_ALLOC below. + */ +struct tee_ioctl_shm_alloc_data { + __u64 size; + __u32 flags; + __s32 fd; +}; +/** + * TEE_IOC_SHM_ALLOC - allocate shared memory + * + * Allocates shared memory between the user space process and secure OS. + * The returned file descriptor is used to map the shared memory into user + * space. The shared memory is freed when the descriptor is closed and the + * memory is unmapped. + */ +#define TEE_IOC_SHM_ALLOC _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 1, \ + struct tee_ioctl_shm_alloc_data) + +/** + * struct tee_ioctl_buf_data - Variable sized buffer + * @buf_ptr: [in] A __user pointer to a buffer + * @buf_len: [in] Length of the buffer above + * + * Used as argument for TEE_IOC_OPEN_SESSION, TEE_IOC_INVOKE, + * TEE_IOC_SUPPL_RECV, and TEE_IOC_SUPPL_SEND below. + */ +struct tee_ioctl_buf_data { + __u64 buf_ptr; + __u64 buf_len; +}; + + +/* + * Attributes for struct tee_ioctl_param, selects field in the union + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_NONE 0 /* parameter not used */ + +/* + * These defines value parameters (struct tee_ioctl_param_value) + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT 1 +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT 2 +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT 3 /* input and output */ + +/* + * These defines shared memory reference parameters (struct + * tee_ioctl_param_memref) + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT 5 +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT 6 +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7 /* input and output */ + +/* + * Mask for the type part of the attribute, leaves room for more types + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_MASK 0xff + +/* + * Matches TEEC_LOGIN_* in GP TEE Client API + * Is only defined for GP compliant TEEs + */ +#define TEE_IOCTL_LOGIN_PUBLIC 0 +#define TEE_IOCTL_LOGIN_USER 1 +#define TEE_IOCTL_LOGIN_GROUP 2 +#define TEE_IOCTL_LOGIN_APPLICATION 4 +#define TEE_IOCTL_LOGIN_USER_APPLICATION 5 +#define TEE_IOCTL_LOGIN_GROUP_APPLICATION 6 + +/** + * struct tee_ioctl_param_memref - memory reference + * @shm_offs: Offset into the shared memory object + * @size: Size of the buffer + * @shm_fd: Shared memory file descriptor + * + * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns a file + * descriptor connected to the shared memory object. A memref can reference + * a part of a shared memory by specifying an offset (@shm_offs) and @size + * of the object. To supply the entire shared memory object set @shm_offs to 0 + * and @size to the previously returned size of the object. + */ +struct tee_ioctl_param_memref { + __u64 shm_offs; + __u64 size; + __s64 shm_fd; +}; + +/** + * struct tee_ioctl_param_value - values + * @a: first value + * @b: second value + * @c: third value + */ +struct tee_ioctl_param_value { + __u64 a; + __u64 b; + __u64 c; +}; + +/** + * struct tee_ioctl_param - parameter + * @attr: attributes + * @memref: a memory reference + * @value: a value + * + * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in + * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and + * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE + * indicates that none of the members are used. + */ +struct tee_ioctl_param { + __u64 attr; + union { + struct tee_ioctl_param_memref memref; + struct tee_ioctl_param_value value; + } u; +}; + +#define TEE_IOCTL_UUID_LEN 16 + +/** + * struct tee_ioctl_open_session_arg - Open session argument + * @uuid: [in] UUID of the Trusted Application + * @clnt_uuid: [in] UUID of client + * @clnt_login: [in] Login class of client, TEE_LOGIN_* above + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @session: [out] Session id + * @ret: [out] return value + * @ret_origin [out] origin of the return value + * @num_params [in] number of parameters following this struct + */ +struct tee_ioctl_open_session_arg { + __u8 uuid[TEE_IOCTL_UUID_LEN]; + __u8 clnt_uuid[TEE_IOCTL_UUID_LEN]; + __u32 clnt_login; + __u32 cancel_id; + __u32 session; + __u32 ret; + __u32 ret_origin; + __u32 num_params; + /* + * this struct is 8 byte aligned since the 'struct tee_ioctl_param' + * which follows requires 8 byte alignment. + * + * Commented out element used to visualize the layout dynamic part + * of the struct. This field is not available at all if + * num_params == 0. + * + * struct tee_ioctl_param params[num_params]; + */ +} __aligned(8); + +/** + * TEE_IOC_OPEN_SESSION - opens a session to a Trusted Application + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_ioctl_open_session_arg followed by any array of struct + * tee_ioctl_param + */ +#define TEE_IOC_OPEN_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 2, \ + struct tee_ioctl_buf_data) + +/** + * struct tee_ioctl_invoke_func_arg - Invokes a function in a Trusted Application + * @func: [in] Trusted Application function, specific to the TA + * @session: [in] Session id + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @ret: [out] return value + * @ret_origin [out] origin of the return value + * @num_params [in] number of parameters following this struct + */ +struct tee_ioctl_invoke_arg { + __u32 func; + __u32 session; + __u32 cancel_id; + __u32 ret; + __u32 ret_origin; + __u32 num_params; + /* + * this struct is 8 byte aligned since the 'struct tee_ioctl_param' + * which follows requires 8 byte alignment. + * + * Commented out element used to visualize the layout dynamic part + * of the struct. This field is not available at all if + * num_params == 0. + * + * struct tee_ioctl_param params[num_params]; + */ +} __aligned(8); + +/** + * TEE_IOC_INVOKE - Invokes a function in a Trusted Application + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_invoke_func_arg followed by any array of struct tee_param + */ +#define TEE_IOC_INVOKE _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 3, \ + struct tee_ioctl_buf_data) + +/** + * struct tee_ioctl_cancel_arg - Cancels an open session or invoke ioctl + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @session: [in] Session id, if the session is opened, else set to 0 + */ +struct tee_ioctl_cancel_arg { + __u32 cancel_id; + __u32 session; +}; +/** + * TEE_IOC_CANCEL - Cancels an open session or invoke + */ +#define TEE_IOC_CANCEL _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 4, \ + struct tee_ioctl_cancel_arg) + +/** + * struct tee_ioctl_close_session_arg - Closes an open session + * @session: [in] Session id + */ +struct tee_ioctl_close_session_arg { + __u32 session; +}; +/** + * TEE_IOC_CLOSE_SESSION - Closes a session + */ +#define TEE_IOC_CLOSE_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 5, \ + struct tee_ioctl_close_session_arg) + +/** + * struct tee_iocl_supp_recv_arg - Receive a request for a supplicant function + * @func: [in] supplicant function + * @num_params [in/out] number of parameters following this struct + * + * @num_params is the number of params that tee-supplicant has room to + * receive when input, @num_params is the number of actual params + * tee-supplicant receives when output. + */ +struct tee_iocl_supp_recv_arg { + __u32 func; + __u32 num_params; + /* + * this struct is 8 byte aligned since the 'struct tee_ioctl_param' + * which follows requires 8 byte alignment. + * + * Commented out element used to visualize the layout dynamic part + * of the struct. This field is not available at all if + * num_params == 0. + * + * struct tee_ioctl_param params[num_params]; + */ +} __aligned(8); +/** + * TEE_IOC_SUPPL_RECV - Receive a request for a supplicant function + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_iocl_supp_recv_arg followed by any array of struct tee_param + */ +#define TEE_IOC_SUPPL_RECV _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 6, \ + struct tee_ioctl_buf_data) + + +/** + * struct tee_iocl_supp_send_arg - Send a response to a received request + * @ret: [out] return value + * @num_params [in] number of parameters following this struct + */ +struct tee_iocl_supp_send_arg { + __u32 ret; + __u32 num_params; + /* + * this struct is 8 byte aligned since the 'struct tee_ioctl_param' + * which follows requires 8 byte alignment. + * + * Commented out element used to visualize the layout dynamic part + * of the struct. This field is not available@all if + * num_params == 0. + * + * struct tee_ioctl_param params[num_params]; + */ +} __aligned(8); +/** + * TEE_IOC_SUPPL_SEND - Receive a request for a supplicant function + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_iocl_supp_send_arg followed by any array of struct tee_param + */ +#define TEE_IOC_SUPPL_SEND _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 7, \ + struct tee_ioctl_buf_data) + + +/* + * Five syscalls are used when communicating with the TEE driver. + * open(): opens the device associated with the driver + * ioctl(): as described above operating on the file descriptor from open() + * close(): two cases + * - closes the device file descriptor + * - closes a file descriptor connected to allocated shared memory + * mmap(): maps shared memory into user space using information from struct + * tee_ioctl_shm_alloc_data + * munmap(): unmaps previously shared memory + */ + +#endif /*__TEE_H*/ -- 1.9.1