b79921741880704e184a8a577dd359df0cda5551
[linux-flexiantxendom0-3.2.10.git] / arch / x86_64 / kernel / ioport.c
1 /*
2  *      linux/arch/x86_64/kernel/ioport.c
3  *
4  * This contains the io-permission bitmap code - written by obz, with changes
5  * by Linus.
6  */
7
8 #include <linux/sched.h>
9 #include <linux/kernel.h>
10 #include <linux/errno.h>
11 #include <linux/types.h>
12 #include <linux/ioport.h>
13 #include <linux/mm.h>
14 #include <linux/smp.h>
15 #include <linux/smp_lock.h>
16 #include <linux/stddef.h>
17 #include <linux/slab.h>
18 #include <asm/io.h>
19
20 /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
21 static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
22 {
23         unsigned long mask;
24         unsigned long *bitmap_base = bitmap + (base / sizeof(unsigned long));
25         unsigned short low_index = base & 0x3f;
26         int length = low_index + extent;
27
28         if (low_index != 0) {
29                 mask = (~0UL << low_index);
30                 if (length < 64)
31                         mask &= ~(~0UL << length);
32                 if (new_value)
33                         *bitmap_base++ |= mask;
34                 else
35                         *bitmap_base++ &= ~mask;
36                 length -= 64;
37         }
38
39         mask = (new_value ? ~0UL : 0UL);
40         while (length >= 64) {
41                 *bitmap_base++ = mask;
42                 length -= 64;
43         }
44
45         if (length > 0) {
46                 mask = ~(~0UL << length);
47                 if (new_value)
48                         *bitmap_base++ |= mask;
49                 else
50                         *bitmap_base++ &= ~mask;
51         }
52 }
53
54
55 /*
56  * this changes the io permissions bitmap in the current task.
57  */
58 asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
59 {
60         struct thread_struct * t = &current->thread;
61         int cpu = get_cpu(); 
62
63         if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
64                 return -EINVAL;
65         if (turn_on && !capable(CAP_SYS_RAWIO))
66                 return -EPERM;
67
68         struct tss_struct * tss = init_tss + cpu; 
69
70         /*
71          * If it's the first ioperm() call in this thread's lifetime, set the
72          * IO bitmap up. ioperm() is much less timing critical than clone(),
73          * this is why we delay this operation until now:
74          */
75         if (!t->io_bitmap_ptr) { 
76                 t->io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
77                 if (!t->io_bitmap_ptr) { 
78                 put_cpu(); 
79                         return -ENOMEM; 
80                 }
81
82                 memset(t->io_bitmap_ptr,0xff,IO_BITMAP_BYTES);
83         }
84
85         /*
86          * do it in the per-thread copy and in the TSS ...
87          */
88         set_bitmap((unsigned long *) t->io_bitmap_ptr, from, num, !turn_on);
89         if (tss->io_map_base != IO_BITMAP_OFFSET) { 
90                 memcpy(tss->io_bitmap, t->io_bitmap_ptr, sizeof(tss->io_bitmap));
91                 tss->io_map_base = IO_BITMAP_OFFSET;
92         } else { 
93         set_bitmap((unsigned long *) tss->io_bitmap, from, num, !turn_on);
94         }
95
96         put_cpu();
97         return 0;
98 }
99
100 /*
101  * sys_iopl has to be used when you want to access the IO ports
102  * beyond the 0x3ff range: to get the full 65536 ports bitmapped
103  * you'd need 8kB of bitmaps/process, which is a bit excessive.
104  *
105  * Here we just change the eflags value on the stack: we allow
106  * only the super-user to do it. This depends on the stack-layout
107  * on system-call entry - see also fork() and the signal handling
108  * code.
109  */
110
111 asmlinkage long sys_iopl(unsigned int level, struct pt_regs regs)
112 {
113         unsigned int old = (regs.eflags >> 12) & 3;
114
115         if (level > 3)
116                 return -EINVAL;
117         /* Trying to gain more privileges? */
118         if (level > old) {
119                 if (!capable(CAP_SYS_RAWIO))
120                         return -EPERM;
121         }
122         regs.eflags = (regs.eflags & 0xffffffffffffcfff) | (level << 12);
123         return 0;
124 }
125
126 void eat_key(void)
127 {
128         if (inb(0x60) & 1) 
129                 inb(0x64);
130 }
131