From f8e5855852d39a9290ddffba18803ae73bdb0539 Mon Sep 17 00:00:00 2001 From: DongHyun Cha Date: Tue, 13 Mar 2018 20:49:20 +0900 Subject: [PATCH] [9610] soc: samsung: Add secmem Change-Id: I89c984a9331e0e9da21254441a36149e73a5c9f4 Signed-off-by: DongHyun Cha Signed-off-by: Jungtae Kim --- drivers/soc/samsung/Makefile | 3 + drivers/soc/samsung/secmem.c | 331 +++++++++++++++++++++++++++++++++++ include/soc/samsung/secmem.h | 67 +++++++ 3 files changed, 401 insertions(+) create mode 100644 drivers/soc/samsung/secmem.c create mode 100644 include/soc/samsung/secmem.h diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index a80a343ca3c3..a51374459cca 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -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 index 000000000000..b0db3fcfadcb --- /dev/null +++ b/drivers/soc/samsung/secmem.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#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 index 000000000000..514c5c4ac0ad --- /dev/null +++ b/include/soc/samsung/secmem.h @@ -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 */ -- 2.20.1