root/kernel/ioport.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ios
  2. dump_io_bitmap
  3. set_bitmap
  4. check_bitmap
  5. sys_ioperm
  6. sys_iopl
  7. snarf_region
  8. check_region
  9. reserve_setup

   1 /*
   2  *      linux/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 
  14 static unsigned long ioport_registrar[IO_BITMAP_SIZE] = {0, /* ... */};
  15 
  16 #define _IODEBUG
  17 
  18 #ifdef IODEBUG
  19 static char * ios(unsigned long l)
     /* [previous][next][first][last][top][bottom][index][help] */
  20 {
  21         static char str[33] = { '\0' };
  22         int i;
  23         unsigned long mask;
  24 
  25         for (i = 0, mask = 0x80000000; i < 32; ++i, mask >>= 1)
  26                 str[i] = (l & mask) ? '1' : '0';
  27         return str;
  28 }
  29 
  30 static void dump_io_bitmap(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  31 {
  32         int i, j;
  33         int numl = sizeof(current->tss.io_bitmap) >> 2;
  34 
  35         for (i = j = 0; j < numl; ++i)
  36         {
  37                 printk("%4d [%3x]: ", 64*i, 64*i);
  38                 printk("%s ", ios(current->tss.io_bitmap[j++]));
  39                 if (j < numl)
  40                         printk("%s", ios(current->tss.io_bitmap[j++]));
  41                 printk("\n");
  42         }
  43 }
  44 #endif
  45 
  46 /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
  47 asmlinkage void set_bitmap(unsigned long *bitmap,
     /* [previous][next][first][last][top][bottom][index][help] */
  48                                                    short base, short extent, int new_value)
  49 {
  50         int mask;
  51         unsigned long *bitmap_base = bitmap + (base >> 5);
  52         unsigned short low_index = base & 0x1f;
  53         int length = low_index + extent;
  54 
  55         if (low_index != 0) {
  56                 mask = (~0 << low_index);
  57                 if (length < 32)
  58                                 mask &= ~(~0 << length);
  59                 if (new_value)
  60                         *bitmap_base++ |= mask;
  61                 else
  62                         *bitmap_base++ &= ~mask;
  63                 length -= 32;
  64         }
  65 
  66         mask = (new_value ? ~0 : 0);
  67         while (length >= 32) {
  68                 *bitmap_base++ = mask;
  69                 length -= 32;
  70         }
  71 
  72         if (length > 0) {
  73                 mask = ~(~0 << length);
  74                 if (new_value)
  75                         *bitmap_base++ |= mask;
  76                 else
  77                         *bitmap_base++ &= ~mask;
  78         }
  79 }
  80 
  81 /* Check for set bits in BITMAP starting at BASE, going to EXTENT. */
  82 asmlinkage int check_bitmap(unsigned long *bitmap, short base, short extent)
     /* [previous][next][first][last][top][bottom][index][help] */
  83 {
  84         int mask;
  85         unsigned long *bitmap_base = bitmap + (base >> 5);
  86         unsigned short low_index = base & 0x1f;
  87         int length = low_index + extent;
  88 
  89         if (low_index != 0) {
  90                 mask = (~0 << low_index);
  91                 if (length < 32)
  92                                 mask &= ~(~0 << length);
  93                 if (*bitmap_base++ & mask)
  94                         return 1;
  95                 length -= 32;
  96         }
  97         while (length >= 32) {
  98                 if (*bitmap_base++ != 0)
  99                         return 1;
 100                 length -= 32;
 101         }
 102 
 103         if (length > 0) {
 104                 mask = ~(~0 << length);
 105                 if (*bitmap_base++ & mask)
 106                         return 1;
 107         }
 108         return 0;
 109 }
 110 
 111 /*
 112  * this changes the io permissions bitmap in the current task.
 113  */
 114 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116         if (from + num <= from)
 117                 return -EINVAL;
 118         if (from + num > IO_BITMAP_SIZE*32)
 119                 return -EINVAL;
 120         if (!suser())
 121                 return -EPERM;
 122 
 123 #ifdef IODEBUG
 124         printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off"));
 125 #endif
 126         set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
 127         return 0;
 128 }
 129 
 130 unsigned int *stack;
 131 
 132 /*
 133  * sys_iopl has to be used when you want to access the IO ports
 134  * beyond the 0x3ff range: to get the full 65536 ports bitmapped
 135  * you'd need 8kB of bitmaps/process, which is a bit excessive.
 136  *
 137  * Here we just change the eflags value on the stack: we allow
 138  * only the super-user to do it. This depends on the stack-layout
 139  * on system-call entry - see also fork() and the signal handling
 140  * code.
 141  */
 142 asmlinkage int sys_iopl(long ebx,long ecx,long edx,
     /* [previous][next][first][last][top][bottom][index][help] */
 143              long esi, long edi, long ebp, long eax, long ds,
 144              long es, long fs, long gs, long orig_eax,
 145              long eip,long cs,long eflags,long esp,long ss)
 146 {
 147         unsigned int level = ebx;
 148 
 149         if (level > 3)
 150                 return -EINVAL;
 151         if (!suser())
 152                 return -EPERM;
 153         *(&eflags) = (eflags & 0xffffcfff) | (level << 12);
 154         return 0;
 155 }
 156 
 157 
 158 void snarf_region(unsigned int from, unsigned int num)
     /* [previous][next][first][last][top][bottom][index][help] */
 159 {
 160         if (from > IO_BITMAP_SIZE*32)
 161                 return;
 162         if (from + num > IO_BITMAP_SIZE*32)
 163                 num = IO_BITMAP_SIZE*32 - from;
 164         set_bitmap(ioport_registrar, from, num, 1);
 165         return;
 166 }
 167 
 168 int check_region(unsigned int from, unsigned int num)
     /* [previous][next][first][last][top][bottom][index][help] */
 169 {
 170         if (from > IO_BITMAP_SIZE*32)
 171                 return 0;
 172         if (from + num > IO_BITMAP_SIZE*32)
 173                 num = IO_BITMAP_SIZE*32 - from;
 174         return check_bitmap(ioport_registrar, from, num);
 175 }
 176 
 177 /* Called from init/main.c to reserve IO ports. */
 178 void reserve_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
 179 {
 180         int i;
 181 
 182         for (i = 1; i < ints[0]; i += 2)
 183                 snarf_region(ints[i], ints[i+1]);
 184 }

/* [previous][next][first][last][top][bottom][index][help] */