[9610] soc: samsung: Add secmem
authorDongHyun Cha <dhyun.cha@samsung.com>
Tue, 13 Mar 2018 11:49:20 +0000 (20:49 +0900)
committerJungi Lee <jungilsi.lee@samsung.com>
Tue, 17 Jul 2018 11:36:20 +0000 (20:36 +0900)
Change-Id: I89c984a9331e0e9da21254441a36149e73a5c9f4
Signed-off-by: DongHyun Cha <dhyun.cha@samsung.com>
Signed-off-by: Jungtae Kim <jt1217.kim@samsung.com>
drivers/soc/samsung/Makefile
drivers/soc/samsung/secmem.c [new file with mode: 0644]
include/soc/samsung/secmem.h [new file with mode: 0644]

index a80a343ca3c37cdf0c915cb0696d9470cdbc6f5f..a51374459cca9b0b9373f5862a22661951df8b29 100644 (file)
@@ -57,3 +57,6 @@ obj-$(CONFIG_EXYNOS_SDM) += exynos-sdm.o
 
 # USI_V2
 obj-$(CONFIG_USI_V2) += usi_v2.o
+
+# secmem
+obj-$(CONFIG_ARCH_EXYNOS)       += secmem.o
diff --git a/drivers/soc/samsung/secmem.c b/drivers/soc/samsung/secmem.c
new file mode 100644 (file)
index 0000000..b0db3fc
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * drivers/soc/samsung/secmem.c
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/export.h>
+#include <linux/pm_qos.h>
+#include <linux/dma-contiguous.h>
+#include <linux/ion_exynos.h>
+#include <linux/smc.h>
+#include <linux/dma-buf.h>
+
+#include <asm/memory.h>
+#include <asm/cacheflush.h>
+
+#include <soc/samsung/secmem.h>
+
+#define SECMEM_DEV_NAME        "s5p-smem"
+
+
+#define DRM_PROT_VER_CHUNK_BASED_PROT  0
+#define DRM_PROT_VER_BUFFER_BASED_PROT 1
+
+struct miscdevice secmem;
+struct secmem_crypto_driver_ftn *crypto_driver;
+
+uint32_t instance_count;
+
+#if defined(CONFIG_SOC_EXYNOS5433)
+static uint32_t secmem_regions[] = {
+       ION_EXYNOS_ID_G2D_WFD,
+       ION_EXYNOS_ID_VIDEO,
+       ION_EXYNOS_ID_SECTBL,
+       ION_EXYNOS_ID_MFC_FW,
+       ION_EXYNOS_ID_MFC_NFW,
+};
+
+static char *secmem_regions_name[] = {
+       "g2d_wfd",      /* 0 */
+       "video",        /* 1 */
+       "sectbl",       /* 2 */
+       "mfc_fw",       /* 3 */
+       "mfc_nfw",      /* 4 */
+       NULL
+};
+#elif defined(CONFIG_SOC_EXYNOS7420)
+static uint32_t secmem_regions[] = {
+       ION_EXYNOS_ID_G2D_WFD,
+       ION_EXYNOS_ID_VIDEO,
+       ION_EXYNOS_ID_VIDEO_EXT,
+       ION_EXYNOS_ID_MFC_FW,
+       ION_EXYNOS_ID_MFC_NFW,
+};
+
+static char *secmem_regions_name[] = {
+       "g2d_wfd",      /* 0 */
+       "video",        /* 1 */
+       "video_ext",    /* 2 */
+       "mfc_fw",       /* 3 */
+       "mfc_nfw",      /* 4 */
+       NULL
+};
+#endif
+
+static bool drm_onoff;
+static DEFINE_MUTEX(drm_lock);
+static DEFINE_MUTEX(smc_lock);
+
+struct secmem_info {
+       struct device   *dev;
+       bool            drm_enabled;
+};
+
+struct protect_info {
+       uint32_t dev;
+       uint32_t enable;
+};
+
+#define SECMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK)))
+
+int drm_enable_locked(struct secmem_info *info, bool enable)
+{
+       if (drm_onoff == enable) {
+               pr_err("%s: DRM is already %s\n", __func__, drm_onoff ? "on" : "off");
+               return -EINVAL;
+       }
+
+       drm_onoff = enable;
+       /*
+        * this will only allow this instance to turn drm_off either by
+        * calling the ioctl or by closing the fd
+        */
+       info->drm_enabled = enable;
+
+       return 0;
+}
+
+static int secmem_open(struct inode *inode, struct file *file)
+{
+       struct miscdevice *miscdev = file->private_data;
+       struct device *dev = miscdev->this_device;
+       struct secmem_info *info;
+
+       info = kzalloc(sizeof(struct secmem_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->dev = dev;
+       file->private_data = info;
+
+       mutex_lock(&drm_lock);
+       instance_count++;
+       mutex_unlock(&drm_lock);
+
+       return 0;
+}
+
+static int secmem_release(struct inode *inode, struct file *file)
+{
+       struct secmem_info *info = file->private_data;
+
+       /* disable drm if we were the one to turn it on */
+       mutex_lock(&drm_lock);
+       instance_count--;
+       if (instance_count == 0) {
+               if (info->drm_enabled) {
+                       int ret;
+                       ret = drm_enable_locked(info, false);
+                       if (ret < 0)
+                               pr_err("fail to lock/unlock drm status. lock = %d\n", false);
+               }
+       }
+
+       mutex_unlock(&drm_lock);
+
+       kfree(info);
+       return 0;
+}
+
+static long secmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       struct secmem_info *info = filp->private_data;
+
+       switch (cmd) {
+#if defined(CONFIG_ION) || defined(CONFIG_ION_EXYNOS)
+       case (uint32_t)SECMEM_IOC_GET_FD_PHYS_ADDR:
+       {
+               struct secfd_info fd_info;
+               struct dma_buf *dmabuf;
+               struct dma_buf_attachment *attachment;
+               struct sg_table *sgt;
+
+               if (copy_from_user(&fd_info, (int __user *)arg,
+                                       sizeof(fd_info)))
+                       return -EFAULT;
+
+               dmabuf = dma_buf_get(fd_info.fd);
+               if (IS_ERR_OR_NULL(dmabuf)) {
+                       pr_err("smem ioctl error(%d)\n", __LINE__);
+                       return -ENOMEM;
+               }
+
+               attachment = dma_buf_attach(dmabuf, info->dev);
+               if (!attachment) {
+                       pr_err("smem ioctl error(%d)\n", __LINE__);
+                       dma_buf_put(dmabuf);
+                       return -ENOMEM;
+               }
+
+               sgt = dma_buf_map_attachment(attachment, DMA_TO_DEVICE);
+               if (!sgt) {
+                       pr_err("smem ioctl error(%d)\n", __LINE__);
+                       dma_buf_detach(dmabuf, attachment);
+                       dma_buf_put(dmabuf);
+                       return -ENOMEM;
+               }
+
+               fd_info.phys = sg_phys(sgt->sgl);
+               pr_debug("%s: physical addr from kernel space = 0x%08x\n",
+                               __func__, (unsigned int)fd_info.phys);
+
+               dma_buf_unmap_attachment(attachment, sgt, DMA_TO_DEVICE);
+               dma_buf_detach(dmabuf, attachment);
+               dma_buf_put(dmabuf);
+
+               if (copy_to_user((void __user *)arg, &fd_info, sizeof(fd_info)))
+                       return -EFAULT;
+               break;
+       }
+#endif
+       case (uint32_t)SECMEM_IOC_GET_DRM_ONOFF:
+               smp_rmb();
+               if (copy_to_user((void __user *)arg, &drm_onoff, sizeof(bool)))
+                       return -EFAULT;
+               break;
+       case (uint32_t)SECMEM_IOC_SET_DRM_ONOFF:
+       {
+               int ret, val = 0;
+
+               if (copy_from_user(&val, (int __user *)arg, sizeof(int)))
+                       return -EFAULT;
+
+               mutex_lock(&drm_lock);
+               if ((info->drm_enabled && !val) ||
+                   (!info->drm_enabled && val)) {
+                       /*
+                        * 1. if we enabled drm, then disable it
+                        * 2. if we don't already hdrm enabled,
+                        *    try to enable it.
+                        */
+                       ret = drm_enable_locked(info, val);
+                       if (ret < 0)
+                               pr_err("fail to lock/unlock drm status. lock = %d\n", val);
+               }
+               mutex_unlock(&drm_lock);
+               break;
+       }
+       case (uint32_t)SECMEM_IOC_GET_CRYPTO_LOCK:
+       {
+               break;
+       }
+       case (uint32_t)SECMEM_IOC_RELEASE_CRYPTO_LOCK:
+       {
+               break;
+       }
+       case (uint32_t)SECMEM_IOC_SET_TZPC:
+       {
+               break;
+       }
+       case (uint32_t)SECMEM_IOC_SET_VIDEO_EXT_PROC:
+       {
+               int val, ret;
+
+               if (copy_from_user(&val, (int __user *)arg, sizeof(int)))
+                       return -EFAULT;
+               mutex_lock(&smc_lock);
+               ret = exynos_smc((uint32_t)(SMC_DRM_VIDEO_PROC), val, 0, 0);
+               if (ret) {
+                       pr_err("Failed to control VIDEO EXT region protection. prot = %d\n", val);
+                       mutex_unlock(&smc_lock);
+                       return -ENOMEM;
+               }
+
+               mutex_unlock(&smc_lock);
+               break;
+       }
+       case (uint32_t)SECMEM_IOC_GET_DRM_PROT_VER:
+       {
+               int val;
+
+               val = DRM_PROT_VER_BUFFER_BASED_PROT;
+               if (copy_to_user((void __user *)arg, &val, sizeof(int)))
+                       return -EFAULT;
+
+               break;
+       }
+       default:
+               return -ENOTTY;
+       }
+
+       return 0;
+}
+
+#if 0
+void secmem_crypto_register(struct secmem_crypto_driver_ftn *ftn)
+{
+       crypto_driver = ftn;
+}
+EXPORT_SYMBOL(secmem_crypto_register);
+
+void secmem_crypto_deregister(void)
+{
+       crypto_driver = NULL;
+}
+EXPORT_SYMBOL(secmem_crypto_deregister);
+#endif
+
+static const struct file_operations secmem_fops = {
+       .owner          = THIS_MODULE,
+       .open           = secmem_open,
+       .release        = secmem_release,
+       .compat_ioctl = secmem_ioctl,
+       .unlocked_ioctl = secmem_ioctl,
+};
+
+struct miscdevice secmem = {
+       .minor  = MISC_DYNAMIC_MINOR,
+       .name   = SECMEM_DEV_NAME,
+       .fops   = &secmem_fops,
+};
+
+static int __init secmem_init(void)
+{
+       int ret;
+
+       ret = misc_register(&secmem);
+       if (ret) {
+               pr_err("%s: SECMEM can't register misc on minor=%d\n",
+                       __func__, MISC_DYNAMIC_MINOR);
+               return ret;
+       }
+
+       crypto_driver = NULL;
+
+       return 0;
+}
+
+static void __exit secmem_exit(void)
+{
+       misc_deregister(&secmem);
+}
+
+module_init(secmem_init);
+module_exit(secmem_exit);
diff --git a/include/soc/samsung/secmem.h b/include/soc/samsung/secmem.h
new file mode 100644 (file)
index 0000000..514c5c4
--- /dev/null
@@ -0,0 +1,67 @@
+/* include/soc/samsung/secmem.h
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * EXYNOS - Secure memory support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_SECMEM_H
+#define __ASM_ARCH_SECMEM_H __FILE__
+
+#define MAX_NAME_LEN   20
+
+struct secchunk_info {
+       int             index;
+       char            name[MAX_NAME_LEN];
+       phys_addr_t     base;
+       size_t          size;
+};
+
+#if defined(CONFIG_ION)
+struct secfd_info {
+       int     fd;
+       unsigned long phys;
+};
+#endif
+
+struct secmem_crypto_driver_ftn {
+       int (*lock) (void);
+       int (*release) (void);
+};
+
+struct secmem_region {
+       char            *virt_addr;
+       unsigned long   phys_addr;
+       unsigned long   len;
+};
+
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+void secmem_crypto_register(struct secmem_crypto_driver_ftn *ftn);
+void secmem_crypto_deregister(void);
+#else
+#define secmem_crypto_register(ftn)
+#define secmem_crypto_deregister()
+#endif
+
+int drm_gsc_enable_locked(bool enable);
+
+#define SECMEM_IOC_CHUNKINFO           _IOWR('S', 1, struct secchunk_info)
+#define SECMEM_IOC_SET_DRM_ONOFF       _IOWR('S', 2, int)
+#define SECMEM_IOC_GET_DRM_ONOFF       _IOWR('S', 3, int)
+#define SECMEM_IOC_GET_CRYPTO_LOCK     _IOR('S', 4, int)
+#define SECMEM_IOC_RELEASE_CRYPTO_LOCK _IOR('S', 5, int)
+#if defined(CONFIG_ION)
+#define SECMEM_IOC_GET_FD_PHYS_ADDR    _IOWR('S', 8, struct secfd_info)
+#endif
+#define SECMEM_IOC_GET_CHUNK_NUM       _IOWR('S', 9, int)
+#define SECMEM_IOC_SET_TZPC            _IOWR('S', 11, struct protect_info)
+#define SECMEM_IOC_SET_PROTECT         _IOWR('S', 12, int)
+#define SECMEM_IOC_SET_VIDEO_EXT_PROC  _IOWR('S', 13, int)
+#define SECMEM_IOC_GET_DRM_PROT_VER    _IOWR('S', 14, int)
+
+#endif /* __ASM_ARCH_SECMEM_H */