comparison vidix/dhahelper/dhahelper.c @ 26901:af5408de478f

Rename kernelhelper to dhahelper, that name is more fitting.
author diego
date Fri, 30 May 2008 19:17:20 +0000
parents
children ad17225e13b4
comparison
equal deleted inserted replaced
26900:9ae10ac43d8c 26901:af5408de478f
1 /*
2 Direct Hardware Access kernel helper
3
4 (C) 2002 Alex Beregszaszi <alex@fsn.hu>
5
6 Accessing hardware from userspace as USER (no root needed!)
7
8 Tested on 2.2.x (2.2.19) and 2.4.x (2.4.3,2.4.17).
9
10 License: GPL
11
12 WARNING! THIS MODULE VIOLATES SEVERAL SECURITY LINES! DON'T USE IT
13 ON PRODUCTION SYSTEMS, ONLY AT HOME, ON A "SINGLE-USER" SYSTEM.
14 NO WARRANTY!
15
16 Tech:
17 Communication between userspace and kernelspace goes over character
18 device using ioctl.
19
20 Usage:
21 mknod -m 666 /dev/dhahelper c 180 0
22
23 Also you can change the major number, setting the "dhahelper_major"
24 module parameter, the default is 180, specified in dhahelper.h.
25
26 Note: do not use other than minor==0, the module forbids it.
27
28 TODO:
29 * do memory mapping without fops:mmap
30 * implement unmap memory
31 * select (request?) a "valid" major number (from Linux project? ;)
32 * make security
33 * is pci handling needed? (libdha does this with lowlevel port funcs)
34 * is mttr handling needed?
35 * test on older kernels (2.0.x (?))
36 */
37
38 #ifndef MODULE
39 #define MODULE
40 #endif
41
42 #ifndef __KERNEL__
43 #define __KERNEL__
44 #endif
45
46 #include <linux/config.h>
47
48 #ifdef CONFIG_MODVERSION
49 #define MODVERSION
50 #include <linux/modversions.h>
51 #endif
52
53 #include <linux/version.h>
54 #include <linux/module.h>
55 #include <linux/types.h>
56 #include <linux/kernel.h>
57 #include <linux/sched.h>
58 #include <linux/mm.h>
59 #include <linux/string.h>
60 #include <linux/errno.h>
61
62 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
63 #include <linux/malloc.h>
64 #else
65 #include <linux/slab.h>
66 #endif
67
68 #include <linux/pci.h>
69 #include <linux/ioport.h>
70 #include <linux/init.h>
71
72 #include <asm/uaccess.h>
73 #include <asm/system.h>
74 #include <asm/io.h>
75
76 #include <linux/mman.h>
77
78 #include <linux/fs.h>
79 #include <linux/unistd.h>
80
81 #include "dhahelper.h"
82
83 MODULE_AUTHOR("Alex Beregszaszi <alex@fsn.hu>");
84 MODULE_DESCRIPTION("Provides userspace access to hardware (security violation!)");
85 #ifdef MODULE_LICENSE
86 MODULE_LICENSE("GPL");
87 #endif
88
89 static int dhahelper_major = DEFAULT_MAJOR;
90 MODULE_PARM(dhahelper_major, "i");
91 MODULE_PARM_DESC(dhahelper_major, "Major number of dhahelper characterdevice");
92
93 /* 0 = silent */
94 /* 1 = report errors (default) */
95 /* 2 = debug */
96 static int dhahelper_verbosity = 1;
97 MODULE_PARM(dhahelper_verbosity, "i");
98 MODULE_PARM_DESC(dhahelper_verbosity, "Level of verbosity (0 = silent, 1 = only errors, 2 = debug)");
99
100 static dhahelper_memory_t last_mem_request;
101
102
103 static int dhahelper_open(struct inode *inode, struct file *file)
104 {
105 if (dhahelper_verbosity > 1)
106 printk(KERN_DEBUG "dhahelper: device opened\n");
107
108 if (MINOR(inode->i_rdev) != 0)
109 return -ENXIO;
110
111 MOD_INC_USE_COUNT;
112
113 return 0;
114 }
115
116 static int dhahelper_release(struct inode *inode, struct file *file)
117 {
118 if (dhahelper_verbosity > 1)
119 printk(KERN_DEBUG "dhahelper: device released\n");
120
121 if (MINOR(inode->i_rdev) != 0)
122 return -ENXIO;
123
124 MOD_DEC_USE_COUNT;
125
126 return 0;
127 }
128
129 static int dhahelper_ioctl(struct inode *inode, struct file *file,
130 unsigned int cmd, unsigned long arg)
131 {
132 if (dhahelper_verbosity > 1)
133 printk(KERN_DEBUG "dhahelper: ioctl(cmd=%x, arg=%lx)\n",
134 cmd, arg);
135
136 if (MINOR(inode->i_rdev) != 0)
137 return -ENXIO;
138
139 switch(cmd)
140 {
141 case DHAHELPER_GET_VERSION:
142 {
143 int version = API_VERSION;
144
145 if (copy_to_user((int *)arg, &version, sizeof(int)))
146 {
147 if (dhahelper_verbosity > 0)
148 printk(KERN_ERR "dhahelper: failed copy to userspace\n");
149 return -EFAULT;
150 }
151
152 break;
153 }
154 case DHAHELPER_PORT:
155 {
156 dhahelper_port_t port;
157
158 if (copy_from_user(&port, (dhahelper_port_t *)arg, sizeof(dhahelper_port_t)))
159 {
160 if (dhahelper_verbosity > 0)
161 printk(KERN_ERR "dhahelper: failed copy from userspace\n");
162 return -EFAULT;
163 }
164
165 switch(port.operation)
166 {
167 case PORT_OP_READ:
168 {
169 switch(port.size)
170 {
171 case 1:
172 port.value = inb(port.addr);
173 break;
174 case 2:
175 port.value = inw(port.addr);
176 break;
177 case 4:
178 port.value = inl(port.addr);
179 break;
180 default:
181 if (dhahelper_verbosity > 0)
182 printk(KERN_ERR "dhahelper: invalid port read size (%d)\n",
183 port.size);
184 return -EINVAL;
185 }
186 break;
187 }
188 case PORT_OP_WRITE:
189 {
190 switch(port.size)
191 {
192 case 1:
193 outb(port.value, port.addr);
194 break;
195 case 2:
196 outw(port.value, port.addr);
197 break;
198 case 4:
199 outl(port.value, port.addr);
200 break;
201 default:
202 if (dhahelper_verbosity > 0)
203 printk(KERN_ERR "dhahelper: invalid port write size (%d)\n",
204 port.size);
205 return -EINVAL;
206 }
207 break;
208 }
209 default:
210 if (dhahelper_verbosity > 0)
211 printk(KERN_ERR "dhahelper: invalid port operation (%d)\n",
212 port.operation);
213 return -EINVAL;
214 }
215
216 /* copy back only if read was performed */
217 if (port.operation == PORT_OP_READ)
218 if (copy_to_user((dhahelper_port_t *)arg, &port, sizeof(dhahelper_port_t)))
219 {
220 if (dhahelper_verbosity > 0)
221 printk(KERN_ERR "dhahelper: failed copy to userspace\n");
222 return -EFAULT;
223 }
224
225 break;
226 }
227 case DHAHELPER_MEMORY:
228 {
229 dhahelper_memory_t mem;
230
231 if (copy_from_user(&mem, (dhahelper_memory_t *)arg, sizeof(dhahelper_memory_t)))
232 {
233 if (dhahelper_verbosity > 0)
234 printk(KERN_ERR "dhahelper: failed copy from userspace\n");
235 return -EFAULT;
236 }
237
238 switch(mem.operation)
239 {
240 case MEMORY_OP_MAP:
241 {
242 #if 1
243 memcpy(&last_mem_request, &mem, sizeof(dhahelper_memory_t));
244 #else
245 mem.ret = do_mmap(file, mem.start, mem.size, PROT_READ|PROT_WRITE,
246 MAP_SHARED, mem.offset);
247 #endif
248
249 break;
250 }
251 case MEMORY_OP_UNMAP:
252 break;
253 default:
254 if (dhahelper_verbosity > 0)
255 printk(KERN_ERR "dhahelper: invalid memory operation (%d)\n",
256 mem.operation);
257 return -EINVAL;
258 }
259
260 if (copy_to_user((dhahelper_memory_t *)arg, &mem, sizeof(dhahelper_memory_t)))
261 {
262 if (dhahelper_verbosity > 0)
263 printk(KERN_ERR "dhahelper: failed copy to userspace\n");
264 return -EFAULT;
265 }
266
267 break;
268 }
269 default:
270 if (dhahelper_verbosity > 0)
271 printk(KERN_ERR "dhahelper: invalid ioctl (%x)\n", cmd);
272 return -EINVAL;
273 }
274
275 return 0;
276 }
277
278 static int dhahelper_mmap(struct file *file, struct vm_area_struct *vma)
279 {
280 if (last_mem_request.operation != MEMORY_OP_MAP)
281 {
282 if (dhahelper_verbosity > 0)
283 printk(KERN_ERR "dhahelper: mapping not requested before mmap\n");
284 return -EFAULT;
285 }
286
287 if (dhahelper_verbosity > 1)
288 printk(KERN_INFO "dhahelper: mapping %x (size: %x)\n",
289 last_mem_request.start+last_mem_request.offset, last_mem_request.size);
290
291 if (remap_page_range(0, last_mem_request.start + last_mem_request.offset,
292 last_mem_request.size, vma->vm_page_prot))
293 {
294 if (dhahelper_verbosity > 0)
295 printk(KERN_ERR "dhahelper: error mapping memory\n");
296 return -EFAULT;
297 }
298
299 return 0;
300 }
301
302 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
303 static struct file_operations dhahelper_fops =
304 {
305 /*llseek*/ NULL,
306 /*read*/ NULL,
307 /*write*/ NULL,
308 /*readdir*/ NULL,
309 /*poll*/ NULL,
310 /*ioctl*/ dhahelper_ioctl,
311 /*mmap*/ dhahelper_mmap,
312 /*open*/ dhahelper_open,
313 /*flush*/ NULL,
314 /*release*/ dhahelper_release,
315 /* zero out the last 5 entries too ? */
316 };
317 #else
318 static struct file_operations dhahelper_fops =
319 {
320 owner: THIS_MODULE,
321 ioctl: dhahelper_ioctl,
322 mmap: dhahelper_mmap,
323 open: dhahelper_open,
324 release: dhahelper_release
325 };
326 #endif
327
328 #if KERNEL_VERSION < KERNEL_VERSION(2,4,0)
329 int init_module(void)
330 #else
331 static int __init init_dhahelper(void)
332 #endif
333 {
334 printk(KERN_INFO "Direct Hardware Access kernel helper (C) Alex Beregszaszi\n");
335
336 if(register_chrdev(dhahelper_major, "dhahelper", &dhahelper_fops))
337 {
338 if (dhahelper_verbosity > 0)
339 printk(KERN_ERR "dhahelper: unable to register character device (major: %d)\n",
340 dhahelper_major);
341 return -EIO;
342 }
343
344 return 0;
345 }
346
347 #if KERNEL_VERSION < KERNEL_VERSION(2,4,0)
348 void cleanup_module(void)
349 #else
350 static void __exit exit_dhahelper(void)
351 #endif
352 {
353 unregister_chrdev(dhahelper_major, "dhahelper");
354 }
355
356 EXPORT_NO_SYMBOLS;
357
358 #if KERNEL_VERSION >= KERNEL_VERSION(2,4,0)
359 module_init(init_dhahelper);
360 module_exit(exit_dhahelper);
361 #endif