Blame view

arch/x86/kernel/ioport.c 2.89 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
   * This contains the io-permission bitmap code - written by obz, with changes
ccafa59a0   mboton@gmail.com   x86: ioport_{32|6...
3
   * by Linus. 32/64 bits code unification by Miguel Botón.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
   */
  
  #include <linux/sched.h>
  #include <linux/kernel.h>
a94156445   Randy Dunlap   [PATCH] capable/c...
8
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/ioport.h>
  #include <linux/smp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
  #include <linux/stddef.h>
  #include <linux/slab.h>
  #include <linux/thread_info.h>
ca906e423   Adrian Bunk   [PATCH] x86: sys_...
16
  #include <linux/syscalls.h>
da1016df8   Akinobu Mita   x86: Use bitmap l...
17
  #include <linux/bitmap.h>
bbc1f698a   Jaswinder Singh   x86: Introducing ...
18
  #include <asm/syscalls.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
  /*
   * this changes the io permissions bitmap in the current task.
   */
  asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
  {
5866e1b49   Jaswinder Singh Rajput   x86: ioport.c fix...
25
26
  	struct thread_struct *t = &current->thread;
  	struct tss_struct *tss;
ccafa59a0   mboton@gmail.com   x86: ioport_{32|6...
27
  	unsigned int i, max_long, bytes, bytes_updated;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
33
34
35
36
37
38
39
  
  	if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
  		return -EINVAL;
  	if (turn_on && !capable(CAP_SYS_RAWIO))
  		return -EPERM;
  
  	/*
  	 * If it's the first ioperm() call in this thread's lifetime, set the
  	 * IO bitmap up. ioperm() is much less timing critical than clone(),
  	 * this is why we delay this operation until now:
  	 */
  	if (!t->io_bitmap_ptr) {
9a211abea   Thomas Gleixner   x86: clean up iop...
40
  		unsigned long *bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
  		if (!bitmap)
  			return -ENOMEM;
  
  		memset(bitmap, 0xff, IO_BITMAP_BYTES);
  		t->io_bitmap_ptr = bitmap;
b3cf25762   Stephane Eranian   [PATCH] i386: use...
46
  		set_thread_flag(TIF_IO_BITMAP);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
53
54
55
56
  	}
  
  	/*
  	 * do it in the per-thread copy and in the TSS ...
  	 *
  	 * Disable preemption via get_cpu() - we must not switch away
  	 * because the ->io_bitmap_max value must match the bitmap
  	 * contents:
  	 */
  	tss = &per_cpu(init_tss, get_cpu());
da1016df8   Akinobu Mita   x86: Use bitmap l...
57
58
59
60
  	if (turn_on)
  		bitmap_clear(t->io_bitmap_ptr, from, num);
  	else
  		bitmap_set(t->io_bitmap_ptr, from, num);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
64
65
66
67
68
69
  
  	/*
  	 * Search for a (possibly new) maximum. This is simple and stupid,
  	 * to keep it obviously correct:
  	 */
  	max_long = 0;
  	for (i = 0; i < IO_BITMAP_LONGS; i++)
  		if (t->io_bitmap_ptr[i] != ~0UL)
  			max_long = i;
ccafa59a0   mboton@gmail.com   x86: ioport_{32|6...
70
71
  	bytes = (max_long + 1) * sizeof(unsigned long);
  	bytes_updated = max(bytes, t->io_bitmap_max);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72

ccafa59a0   mboton@gmail.com   x86: ioport_{32|6...
73
  	t->io_bitmap_max = bytes;
ccafa59a0   mboton@gmail.com   x86: ioport_{32|6...
74
75
  	/* Update the TSS: */
  	memcpy(tss->io_bitmap, t->io_bitmap_ptr, bytes_updated);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
83
84
85
86
  
  	put_cpu();
  
  	return 0;
  }
  
  /*
   * sys_iopl has to be used when you want to access the IO ports
   * beyond the 0x3ff range: to get the full 65536 ports bitmapped
   * you'd need 8kB of bitmaps/process, which is a bit excessive.
   *
65ea5b034   H. Peter Anvin   x86: rename the s...
87
   * Here we just change the flags value on the stack: we allow
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
   * only the super-user to do it. This depends on the stack-layout
   * on system-call entry - see also fork() and the signal handling
   * code.
   */
27f59559d   Brian Gerst   x86: Merge sys_iopl
92
  long sys_iopl(unsigned int level, struct pt_regs *regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  {
65ea5b034   H. Peter Anvin   x86: rename the s...
94
  	unsigned int old = (regs->flags >> 12) & 3;
27f59559d   Brian Gerst   x86: Merge sys_iopl
95
  	struct thread_struct *t = &current->thread;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
100
101
102
103
  
  	if (level > 3)
  		return -EINVAL;
  	/* Trying to gain more privileges? */
  	if (level > old) {
  		if (!capable(CAP_SYS_RAWIO))
  			return -EPERM;
  	}
ccafa59a0   mboton@gmail.com   x86: ioport_{32|6...
104
  	regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12);
a1bf250a6   Chris Wright   x86: refactor iop...
105
106
  	t->iopl = level << 12;
  	set_iopl_mask(t->iopl);
27f59559d   Brian Gerst   x86: Merge sys_iopl
107
108
109
  
  	return 0;
  }