1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 */
5
6 #include "xpm_misc.h"
7
8 #include <linux/mm.h>
9 #include <linux/mman.h>
10 #include <linux/file.h>
11 #include <linux/compat.h>
12 #include <linux/mm_types.h>
13 #include <linux/miscdevice.h>
14 #include <linux/xpm_types.h>
15 #include "xpm_log.h"
16 #include "xpm_report.h"
17
18 #define XPM_SET_REGION _IOW('x', 0x01, struct xpm_region_info)
19
xpm_set_region(unsigned long addr_base,unsigned long length)20 static int xpm_set_region(unsigned long addr_base, unsigned long length)
21 {
22 int ret = 0;
23 unsigned long addr;
24 struct mm_struct *mm = current->mm;
25
26 if (!mm)
27 return -EINVAL;
28
29 if (mmap_write_lock_killable(mm))
30 return -EINTR;
31
32 if ((mm->xpm_region.addr_start != 0) ||
33 (mm->xpm_region.addr_end != 0)) {
34 xpm_log_info("xpm region has been set");
35 goto exit;
36 }
37
38 addr = get_unmapped_area(NULL, addr_base, length, 0, 0);
39 if (IS_ERR_VALUE(addr) || (ULONG_MAX - addr_base < length)) {
40 xpm_log_error("xpm get unmmaped area failed");
41 ret = -EINVAL;
42 goto exit;
43 }
44
45 mm->xpm_region.addr_start = addr;
46 mm->xpm_region.addr_end = addr + length;
47 exit:
48 mmap_write_unlock(mm);
49 return ret;
50 }
51
xpm_ioctl(struct file * file,unsigned int cmd,unsigned long arg)52 static long xpm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
53 {
54 int ret;
55 struct xpm_region_info info = {0};
56
57 if (unlikely(copy_from_user(&info, (void __user *)(uintptr_t)arg,
58 sizeof(struct xpm_region_info))))
59 return -EFAULT;
60
61 switch (cmd) {
62 case XPM_SET_REGION:
63 ret = xpm_set_region(info.addr_base, info.length);
64 break;
65 default:
66 xpm_log_error("xpm ioctl cmd error, cmd = %d", cmd);
67 ret = -EINVAL;
68 break;
69 }
70
71 return ret;
72 }
73
74 #ifdef CONFIG_COMPAT
xpm_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)75 static long xpm_compat_ioctl(struct file *file, unsigned int cmd,
76 unsigned long arg)
77 {
78 return 0;
79 }
80 #endif
81
xpm_open(struct inode * inode,struct file * file)82 static int xpm_open(struct inode *inode, struct file *file)
83 {
84 return 0;
85 }
86
xpm_release(struct inode * inode,struct file * file)87 static int xpm_release(struct inode *inode, struct file *file)
88 {
89 return 0;
90 }
91
92 static const struct file_operations xpm_fops = {
93 .owner = THIS_MODULE,
94 .open = xpm_open,
95 .release = xpm_release,
96 .unlocked_ioctl = xpm_ioctl,
97 #ifdef CONFIG_COMPAT
98 .compat_ioctl = xpm_compat_ioctl,
99 #endif
100 };
101
102 static struct miscdevice xpm_misc = {
103 .minor = MISC_DYNAMIC_MINOR,
104 .name = "xpm",
105 .fops = &xpm_fops,
106 };
107
xpm_register_misc_device(void)108 int xpm_register_misc_device(void)
109 {
110 return misc_register(&xpm_misc);
111 }
112
xpm_deregister_misc_device(void)113 void xpm_deregister_misc_device(void)
114 {
115 misc_deregister(&xpm_misc);
116 }
117