mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
e61f09a014
PD#SWPL-126447 Problem: Unifykey attach crash. Solution: Checks whether secmon memory is mapped Verify: txhd2 be311 Change-Id: Ifc1a973b3cc93b090ad58932bb3d5d8e413d8de5 Signed-off-by: yao zhang1 <yao.zhang1@amlogic.com>
308 lines
7.1 KiB
C
308 lines
7.1 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
// #define DEBUG
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/arm-smccc.h>
|
|
#include <linux/io.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/kallsyms.h>
|
|
#include "security_key.h"
|
|
|
|
#if IS_ENABLED(CONFIG_ARM)
|
|
#include <linux/of.h>
|
|
#include <linux/of_fdt.h>
|
|
|
|
static struct device_node *ofdts_node;
|
|
static int pfn_valid_flag;
|
|
#endif
|
|
|
|
static DEFINE_SPINLOCK(storage_lock);
|
|
static int storage_init_status;
|
|
static struct bl31_storage_share_mem *share_mem;
|
|
|
|
static unsigned long storage_smc_ops(u64 func)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
arm_smccc_smc((unsigned long)func, 0, 0, 0, 0, 0, 0, 0, &res);
|
|
return res.a0;
|
|
}
|
|
|
|
void *secure_storage_getbuf(u32 *size)
|
|
{
|
|
if (storage_init_status == 1) {
|
|
*size = share_mem->size;
|
|
return (void *)(share_mem->block);
|
|
}
|
|
|
|
*size = 0;
|
|
return NULL;
|
|
}
|
|
|
|
unsigned long secure_storage_write(u8 *keyname, u8 *keybuf,
|
|
u32 keylen, u32 keyattr)
|
|
{
|
|
u32 *input;
|
|
u32 namelen;
|
|
u8 *keydata;
|
|
u8 *name;
|
|
unsigned long ret;
|
|
unsigned long lockflags;
|
|
|
|
if (storage_init_status != 1)
|
|
return RET_EUND;
|
|
|
|
namelen = strlen(keyname);
|
|
if (namelen + keylen + 12 > share_mem->size)
|
|
return RET_EMEM;
|
|
|
|
spin_lock_irqsave(&storage_lock, lockflags);
|
|
input = (u32 *)(share_mem->in);
|
|
*input++ = namelen;
|
|
*input++ = keylen;
|
|
*input++ = keyattr;
|
|
name = (u8 *)input;
|
|
memcpy(name, keyname, namelen);
|
|
keydata = name + namelen;
|
|
memcpy(keydata, keybuf, keylen);
|
|
ret = storage_smc_ops(BL31_STORAGE_WRITE);
|
|
spin_unlock_irqrestore(&storage_lock, lockflags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned long secure_storage_read(u8 *keyname, u8 *keybuf,
|
|
u32 keylen, u32 *readlen)
|
|
{
|
|
u32 *input;
|
|
u32 *output;
|
|
u32 namelen;
|
|
u8 *name;
|
|
u8 *buf;
|
|
unsigned long ret;
|
|
unsigned long lockflags;
|
|
|
|
if (storage_init_status != 1)
|
|
return RET_EUND;
|
|
|
|
namelen = strlen(keyname);
|
|
if (namelen + 8 > share_mem->size)
|
|
return RET_EMEM;
|
|
|
|
spin_lock_irqsave(&storage_lock, lockflags);
|
|
input = (u32 *)(share_mem->in);
|
|
output = (u32 *)(share_mem->out);
|
|
*input++ = namelen;
|
|
*input++ = keylen;
|
|
name = (u8 *)input;
|
|
memcpy(name, keyname, namelen);
|
|
ret = storage_smc_ops(BL31_STORAGE_READ);
|
|
if (ret == RET_OK) {
|
|
*readlen = *output;
|
|
if (*readlen > keylen)
|
|
*readlen = keylen;
|
|
buf = (u8 *)(output + 1);
|
|
memcpy(keybuf, buf, *readlen);
|
|
}
|
|
spin_unlock_irqrestore(&storage_lock, lockflags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned long secure_storage_verify(u8 *keyname, u8 *hashbuf)
|
|
{
|
|
u32 *input;
|
|
u32 *output;
|
|
u32 namelen;
|
|
u8 *name;
|
|
unsigned long ret;
|
|
unsigned long lockflags;
|
|
|
|
if (storage_init_status != 1)
|
|
return RET_EUND;
|
|
|
|
namelen = strlen(keyname);
|
|
if (namelen + 4 > share_mem->size)
|
|
return RET_EMEM;
|
|
|
|
spin_lock_irqsave(&storage_lock, lockflags);
|
|
input = (u32 *)(share_mem->in);
|
|
output = (u32 *)(share_mem->out);
|
|
*input++ = namelen;
|
|
name = (u8 *)input;
|
|
memcpy(name, keyname, namelen);
|
|
ret = storage_smc_ops(BL31_STORAGE_VERIFY);
|
|
if (ret == RET_OK)
|
|
memcpy(hashbuf, (u8 *)output, 32);
|
|
spin_unlock_irqrestore(&storage_lock, lockflags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned long secure_storage_query(u8 *key_name, u32 *retval)
|
|
{
|
|
u32 *input;
|
|
u32 *output;
|
|
u32 namelen;
|
|
u8 *name;
|
|
unsigned long ret;
|
|
unsigned long lockflags;
|
|
|
|
if (storage_init_status != 1)
|
|
return RET_EUND;
|
|
|
|
namelen = strlen(key_name);
|
|
if (namelen + 4 > share_mem->size)
|
|
return RET_EMEM;
|
|
|
|
spin_lock_irqsave(&storage_lock, lockflags);
|
|
input = (u32 *)(share_mem->in);
|
|
output = (u32 *)(share_mem->out);
|
|
*input++ = namelen;
|
|
name = (u8 *)input;
|
|
memcpy(name, key_name, namelen);
|
|
ret = storage_smc_ops(BL31_STORAGE_QUERY);
|
|
if (ret == RET_OK)
|
|
*retval = *output;
|
|
spin_unlock_irqrestore(&storage_lock, lockflags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned long secure_storage_tell(u8 *keyname, u32 *retval)
|
|
{
|
|
u32 *input;
|
|
u32 *output;
|
|
u32 namelen;
|
|
u8 *name;
|
|
unsigned long ret;
|
|
unsigned long lockflags;
|
|
|
|
if (storage_init_status != 1)
|
|
return RET_EUND;
|
|
|
|
namelen = strlen(keyname);
|
|
if (namelen + 4 > share_mem->size)
|
|
return RET_EMEM;
|
|
|
|
spin_lock_irqsave(&storage_lock, lockflags);
|
|
input = (u32 *)(share_mem->in);
|
|
output = (u32 *)(share_mem->out);
|
|
*input++ = namelen;
|
|
name = (u8 *)input;
|
|
memcpy(name, keyname, namelen);
|
|
ret = storage_smc_ops(BL31_STORAGE_TELL);
|
|
if (ret == RET_OK)
|
|
*retval = *output;
|
|
spin_unlock_irqrestore(&storage_lock, lockflags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned long secure_storage_status(u8 *keyname, u32 *retval)
|
|
{
|
|
u32 *input;
|
|
u32 *output;
|
|
u32 namelen;
|
|
u8 *name;
|
|
u64 ret;
|
|
unsigned long lockflags;
|
|
|
|
if (storage_init_status != 1)
|
|
return RET_EUND;
|
|
|
|
namelen = strlen(keyname);
|
|
if (namelen + 4 > share_mem->size)
|
|
return RET_EMEM;
|
|
|
|
spin_lock_irqsave(&storage_lock, lockflags);
|
|
input = (u32 *)(share_mem->in);
|
|
output = (u32 *)(share_mem->out);
|
|
*input++ = namelen;
|
|
name = (u8 *)input;
|
|
memcpy(name, keyname, namelen);
|
|
ret = storage_smc_ops(BL31_STORAGE_STATUS);
|
|
if (ret == RET_OK)
|
|
*retval = *output;
|
|
spin_unlock_irqrestore(&storage_lock, lockflags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int __init security_key_init(struct platform_device *pdev)
|
|
{
|
|
unsigned long phy_in;
|
|
unsigned long phy_out;
|
|
unsigned long phy_block;
|
|
|
|
storage_init_status = -1;
|
|
|
|
share_mem = devm_kzalloc(&pdev->dev, sizeof(*share_mem), GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(share_mem)) {
|
|
pr_err("fail to alloc mem for struct share_mem\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
phy_in = storage_smc_ops(BL31_STORAGE_IN);
|
|
phy_out = storage_smc_ops(BL31_STORAGE_OUT);
|
|
phy_block = storage_smc_ops(BL31_STORAGE_BLOCK);
|
|
share_mem->size = storage_smc_ops(BL31_STORAGE_SIZE);
|
|
|
|
if (!phy_in || (int)phy_in == SMC_UNK ||
|
|
!phy_out || (int)phy_out == SMC_UNK ||
|
|
!phy_block || (int)phy_block == SMC_UNK ||
|
|
!(share_mem->size) || ((int)share_mem->size) == SMC_UNK) {
|
|
pr_err("fail to obtain phy addr of shared mem\n");
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_ARM)
|
|
ofdts_node = of_find_node_by_name(NULL, "linux,secmon");
|
|
if (!ofdts_node)
|
|
return -EINVAL;
|
|
|
|
if (of_property_read_bool(ofdts_node, "no-map"))
|
|
pfn_valid_flag = 0;
|
|
else
|
|
pfn_valid_flag = 1;
|
|
#endif
|
|
|
|
/*
|
|
* The BL31 shared mem for key storage is
|
|
* part of secure monitor, and all of the
|
|
* mem locates at lowmem region, so its
|
|
* okay to call phys_to_virt directly
|
|
*/
|
|
#ifdef CONFIG_ARM64
|
|
if (pfn_is_map_memory(__phys_to_pfn(phy_in))) {
|
|
#else
|
|
if (pfn_valid_flag) {
|
|
#endif
|
|
share_mem->in = (void __iomem *)phys_to_virt(phy_in);
|
|
share_mem->out = (void __iomem *)phys_to_virt(phy_out);
|
|
share_mem->block = (void __iomem *)phys_to_virt(phy_block);
|
|
} else {
|
|
share_mem->in = ioremap_cache(phy_in, share_mem->size);
|
|
share_mem->out = ioremap_cache(phy_out, share_mem->size);
|
|
share_mem->block = ioremap_cache(phy_block, share_mem->size);
|
|
}
|
|
|
|
pr_info("storage in: 0x%lx, out: 0x%lx, block: 0x%lx\n",
|
|
(long)(share_mem->in), (long)(share_mem->out),
|
|
(long)(share_mem->block));
|
|
|
|
if (!(share_mem->in) || !(share_mem->out) || !(share_mem->block)) {
|
|
pr_err("fail to obtain virtual addr of shared mem\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
storage_init_status = 1;
|
|
pr_info("security_key init done!\n");
|
|
return 0;
|
|
}
|