linux-old/arch/i386/kernel/ioport.c
<<
>>
Prefs
   1/*
   2 *      linux/arch/i386/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
  18/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
  19static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
  20{
  21        int mask;
  22        unsigned long *bitmap_base = bitmap + (base >> 5);
  23        unsigned short low_index = base & 0x1f;
  24        int length = low_index + extent;
  25
  26        if (low_index != 0) {
  27                mask = (~0 << low_index);
  28                if (length < 32)
  29                                mask &= ~(~0 << length);
  30                if (new_value)
  31                        *bitmap_base++ |= mask;
  32                else
  33                        *bitmap_base++ &= ~mask;
  34                length -= 32;
  35        }
  36
  37        mask = (new_value ? ~0 : 0);
  38        while (length >= 32) {
  39                *bitmap_base++ = mask;
  40                length -= 32;
  41        }
  42
  43        if (length > 0) {
  44                mask = ~(~0 << length);
  45                if (new_value)
  46                        *bitmap_base++ |= mask;
  47                else
  48                        *bitmap_base++ &= ~mask;
  49        }
  50}
  51
  52/*
  53 * this changes the io permissions bitmap in the current task.
  54 */
  55asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
  56{
  57        struct thread_struct * t = &current->thread;
  58        struct tss_struct * tss = init_tss + smp_processor_id();
  59
  60        if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
  61                return -EINVAL;
  62        if (turn_on && !capable(CAP_SYS_RAWIO))
  63                return -EPERM;
  64        /*
  65         * If it's the first ioperm() call in this thread's lifetime, set the
  66         * IO bitmap up. ioperm() is much less timing critical than clone(),
  67         * this is why we delay this operation until now:
  68         */
  69        if (!t->ioperm) {
  70                /*
  71                 * just in case ...
  72                 */
  73                memset(t->io_bitmap,0xff,(IO_BITMAP_SIZE+1)*4);
  74                t->ioperm = 1;
  75        }
  76
  77        /*
  78         * do it in the per-thread copy and in the TSS ...
  79         */
  80        set_bitmap(t->io_bitmap, from, num, !turn_on);
  81        if (tss->bitmap == IO_BITMAP_OFFSET) { /* already active? */
  82                set_bitmap(tss->io_bitmap, from, num, !turn_on);
  83        } else {
  84                memcpy(tss->io_bitmap, t->io_bitmap, IO_BITMAP_BYTES);
  85                tss->bitmap = IO_BITMAP_OFFSET; /* Activate it in the TSS */
  86        }
  87
  88        return 0;
  89}
  90
  91/*
  92 * sys_iopl has to be used when you want to access the IO ports
  93 * beyond the 0x3ff range: to get the full 65536 ports bitmapped
  94 * you'd need 8kB of bitmaps/process, which is a bit excessive.
  95 *
  96 * Here we just change the eflags value on the stack: we allow
  97 * only the super-user to do it. This depends on the stack-layout
  98 * on system-call entry - see also fork() and the signal handling
  99 * code.
 100 */
 101
 102asmlinkage int sys_iopl(unsigned long unused)
 103{
 104        struct pt_regs * regs = (struct pt_regs *) &unused;
 105        unsigned int level = regs->ebx;
 106        unsigned int old = (regs->eflags >> 12) & 3;
 107
 108        if (level > 3)
 109                return -EINVAL;
 110        /* Trying to gain more privileges? */
 111        if (level > old) {
 112                if (!capable(CAP_SYS_RAWIO))
 113                        return -EPERM;
 114        }
 115        regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12);
 116        return 0;
 117}
 118
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.