278 lines
6.8 KiB
C
278 lines
6.8 KiB
C
|
#include <linux/proc_fs.h>
|
||
|
#include <linux/sec_debug.h>
|
||
|
#include <linux/moduleparam.h>
|
||
|
#include <linux/uaccess.h>
|
||
|
#include <linux/memblock.h>
|
||
|
#include <linux/of.h>
|
||
|
#include <linux/of_reserved_mem.h>
|
||
|
#include <linux/seq_file.h>
|
||
|
|
||
|
/* Override the default prefix for the compatibility with other models */
|
||
|
#undef MODULE_PARAM_PREFIX
|
||
|
#define MODULE_PARAM_PREFIX "sec_debug."
|
||
|
|
||
|
#define ENABLE_SDCARD_RAMDUMP (0x73646364)
|
||
|
#define MAGIC_SDR_FOR_MINFORM (0x3)
|
||
|
#define ENABLE_STORAGE_RAMDUMP (0x42544456)
|
||
|
#define MAGIC_STR_FOR_MINFORM (0xC)
|
||
|
#define OFFSET_SDR_FOR_MINFORM (0x0)
|
||
|
#define MASK_SDR_FOR_MINFORM (0xF)
|
||
|
|
||
|
#define SHA256_DIGEST_SIZE 32
|
||
|
#define SHA256_BLOCK_SIZE 64
|
||
|
#define SHA256_DIGEST_LENGTH SHA256_DIGEST_SIZE
|
||
|
|
||
|
void sec_set_reboot_magic(int magic);
|
||
|
|
||
|
static unsigned int dump_sink;
|
||
|
static unsigned int upload_count;
|
||
|
static int initialized;
|
||
|
|
||
|
static int sec_sdcard_ramdump(const char *val, const struct kernel_param *kp)
|
||
|
{
|
||
|
kstrtouint(val, 16, &dump_sink);
|
||
|
pr_crit("%s: %s %x\n", __func__, val, dump_sink);
|
||
|
|
||
|
if (!initialized)
|
||
|
return 0;
|
||
|
|
||
|
if (dump_sink == ENABLE_SDCARD_RAMDUMP) {
|
||
|
sec_set_reboot_magic(MAGIC_SDR_FOR_MINFORM);
|
||
|
} else if (dump_sink == ENABLE_STORAGE_RAMDUMP) {
|
||
|
sec_set_reboot_magic(MAGIC_STR_FOR_MINFORM);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct kernel_param_ops sec_dump_sink_ops = {
|
||
|
.set = sec_sdcard_ramdump,
|
||
|
.get = param_get_uint,
|
||
|
};
|
||
|
|
||
|
module_param_cb(dump_sink, &sec_dump_sink_ops, &dump_sink, 0644);
|
||
|
|
||
|
static phys_addr_t sec_rdx_bootdev_paddr;
|
||
|
static unsigned long long sec_rdx_bootdev_size;
|
||
|
static DEFINE_MUTEX(rdx_bootdev_mutex);
|
||
|
|
||
|
static void sec_free_rdx_bootdev(phys_addr_t paddr, u64 size)
|
||
|
{
|
||
|
/* caution : this fuction should be called in rdx_bootdev_mutex protected region. */
|
||
|
unsigned long pfn_start, pfn_end, pfn_idx;
|
||
|
int ret;
|
||
|
|
||
|
pr_info("start (0x%llx, 0x%llx)\n", paddr, size);
|
||
|
|
||
|
if (!sec_rdx_bootdev_paddr) {
|
||
|
pr_err("reserved addr is null\n");
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
if (!sec_rdx_bootdev_size) {
|
||
|
pr_err("reserved size is zero\n");
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
if (paddr < sec_rdx_bootdev_paddr) {
|
||
|
pr_err("paddr is not valid\n");
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
if (paddr + size > sec_rdx_bootdev_paddr + sec_rdx_bootdev_size) {
|
||
|
pr_err("range is not valid\n");
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
memset(phys_to_virt(paddr), 0, size);
|
||
|
|
||
|
ret = memblock_free(paddr, size);
|
||
|
if (ret) {
|
||
|
pr_err("memblock_free failed (ret : %d)\n", ret);
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
// free_memsize_reserved(paddr, size);
|
||
|
|
||
|
pfn_start = paddr >> PAGE_SHIFT;
|
||
|
pfn_end = (paddr + size) >> PAGE_SHIFT;
|
||
|
for (pfn_idx = pfn_start; pfn_idx < pfn_end; pfn_idx++)
|
||
|
free_reserved_page(pfn_to_page(pfn_idx));
|
||
|
|
||
|
if (sec_rdx_bootdev_paddr == paddr) {
|
||
|
sec_rdx_bootdev_paddr = 0;
|
||
|
}
|
||
|
|
||
|
sec_rdx_bootdev_size -= size;
|
||
|
|
||
|
out:
|
||
|
pr_info("end\n");
|
||
|
}
|
||
|
|
||
|
static ssize_t sec_rdx_bootdev_proc_write(struct file *file,
|
||
|
const char __user *buf, size_t count, loff_t *ppos)
|
||
|
{
|
||
|
int err = 0;
|
||
|
struct fiemap *pfiemap;
|
||
|
phys_addr_t paddr;
|
||
|
u64 size;
|
||
|
|
||
|
mutex_lock(&rdx_bootdev_mutex);
|
||
|
|
||
|
paddr = sec_rdx_bootdev_paddr;
|
||
|
size = sec_rdx_bootdev_size;
|
||
|
|
||
|
if (!sec_rdx_bootdev_paddr) {
|
||
|
pr_err("sec_rdx_bootdev_paddr is null\n");
|
||
|
err = -EFAULT;
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
if (!buf) {
|
||
|
err = -ENODEV;
|
||
|
} else {
|
||
|
if (count > sec_rdx_bootdev_size) {
|
||
|
pr_err("size is wrong %lu > %u\n", count, sec_rdx_bootdev_size);
|
||
|
err = -EINVAL;
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
if (copy_from_user(phys_to_virt(sec_rdx_bootdev_paddr),
|
||
|
buf, count)) {
|
||
|
pr_err("copy_from_user failed\n");
|
||
|
err = -EFAULT;
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
pfiemap = phys_to_virt(sec_rdx_bootdev_paddr) + SHA256_DIGEST_LENGTH;
|
||
|
paddr = virt_to_phys(&pfiemap->fm_extents[pfiemap->fm_mapped_extents]);
|
||
|
if (paddr <
|
||
|
sec_rdx_bootdev_paddr + sec_rdx_bootdev_size) {
|
||
|
paddr = ALIGN(paddr, PAGE_SIZE);
|
||
|
size = paddr - sec_rdx_bootdev_paddr;
|
||
|
size = sec_rdx_bootdev_size - size;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
out:
|
||
|
sec_free_rdx_bootdev(paddr, size);
|
||
|
mutex_unlock(&rdx_bootdev_mutex);
|
||
|
return err < 0 ? err : count;
|
||
|
}
|
||
|
|
||
|
static const struct file_operations sec_rdx_bootdev_fops = {
|
||
|
.owner = THIS_MODULE,
|
||
|
.write = sec_rdx_bootdev_proc_write,
|
||
|
};
|
||
|
|
||
|
static int __init sec_set_upload_count(char *arg)
|
||
|
{
|
||
|
get_option(&arg, &upload_count);
|
||
|
return 0;
|
||
|
}
|
||
|
early_param("sec_debug.upload_count", sec_set_upload_count);
|
||
|
|
||
|
static int sec_upload_count_show(struct seq_file *m, void *v)
|
||
|
{
|
||
|
seq_printf(m, "%d", upload_count);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int sec_upload_count_open(struct inode *inode, struct file *file)
|
||
|
{
|
||
|
return single_open(file, sec_upload_count_show, NULL);
|
||
|
}
|
||
|
|
||
|
static const struct file_operations sec_upload_count_proc_fops = {
|
||
|
.open = sec_upload_count_open,
|
||
|
.read = seq_read,
|
||
|
.llseek = seq_lseek,
|
||
|
.release = single_release,
|
||
|
};
|
||
|
|
||
|
static int __init sec_map_rdx_bootdev_region(void)
|
||
|
{
|
||
|
struct device_node *parent, *node;
|
||
|
int ret = 0;
|
||
|
u32 temp[4];
|
||
|
|
||
|
parent = of_find_node_by_path("/reserved-memory");
|
||
|
if (!parent) {
|
||
|
pr_err("%s, failed to find reserved-memory node\n", __func__);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
node = of_find_node_by_name(parent, "sec_rdx_bootdev");
|
||
|
if (!node) {
|
||
|
pr_err("%s, failed to find sec_rdx_bootdev\n", __func__);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
ret = of_property_read_u32_array(node, "reg", &temp[0], 4);
|
||
|
if (ret) {
|
||
|
pr_err("%s, failed to get address from node %d\n", __func__, ret);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
mutex_lock(&rdx_bootdev_mutex);
|
||
|
sec_rdx_bootdev_paddr = temp[0];
|
||
|
sec_rdx_bootdev_paddr = (sec_rdx_bootdev_paddr << 32);
|
||
|
sec_rdx_bootdev_paddr += temp[1];
|
||
|
sec_rdx_bootdev_size = temp[2];
|
||
|
sec_rdx_bootdev_size = (sec_rdx_bootdev_size << 32);
|
||
|
sec_rdx_bootdev_size += temp[3];
|
||
|
|
||
|
pr_info("%s, sec_rdx_bootdev : 0x%llx, 0x%llx\n", __func__,
|
||
|
sec_rdx_bootdev_paddr, sec_rdx_bootdev_size);
|
||
|
|
||
|
pr_info("%s, sec_rdx_bootdev2 : 0x%x, 0x%x\n", __func__,
|
||
|
temp[2], temp[3]);
|
||
|
|
||
|
if (!sec_rdx_bootdev_paddr || !sec_rdx_bootdev_size) {
|
||
|
pr_err("%s, failed to get address from node\n", __func__);
|
||
|
mutex_unlock(&rdx_bootdev_mutex);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (!SEC_DEBUG_LEVEL(kernel)) {
|
||
|
pr_info("%s, sec_debug is not enabled\n", __func__);
|
||
|
sec_free_rdx_bootdev(sec_rdx_bootdev_paddr, sec_rdx_bootdev_size);
|
||
|
mutex_unlock(&rdx_bootdev_mutex);
|
||
|
return 0;
|
||
|
}
|
||
|
memset(phys_to_virt(sec_rdx_bootdev_paddr), 0, SHA256_DIGEST_LENGTH);
|
||
|
|
||
|
mutex_unlock(&rdx_bootdev_mutex);
|
||
|
return 0;
|
||
|
}
|
||
|
arch_initcall_sync(sec_map_rdx_bootdev_region);
|
||
|
|
||
|
static int __init sec_dump_sink_init(void)
|
||
|
{
|
||
|
struct proc_dir_entry *entry;
|
||
|
|
||
|
entry = proc_create("rdx_bootdev", 0220, NULL, &sec_rdx_bootdev_fops);
|
||
|
|
||
|
if (!entry) {
|
||
|
pr_err("%s: fail to create proc entry (rdx_bootdev)\n", __func__);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
entry = proc_create("upload_count", 0440, NULL, &sec_upload_count_proc_fops);
|
||
|
|
||
|
if (!entry) {
|
||
|
pr_err("%s: fail to create proc entry (upload_count)\n", __func__);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
pr_info("%s: success to create proc entry\n", __func__);
|
||
|
initialized = 1;
|
||
|
if (dump_sink == ENABLE_SDCARD_RAMDUMP) {
|
||
|
sec_set_reboot_magic(MAGIC_SDR_FOR_MINFORM);
|
||
|
} else if (dump_sink == ENABLE_STORAGE_RAMDUMP) {
|
||
|
sec_set_reboot_magic(MAGIC_STR_FOR_MINFORM);
|
||
|
}
|
||
|
pr_info("%s: dump_sink set to 0x%x\n", __func__, dump_sink);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
device_initcall(sec_dump_sink_init);
|
||
|
|