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. get_ioport_list
  6. sys_ioperm
  7. sys_iopl
  8. snarf_region
  9. release_region
  10. check_region
  11. 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 int get_ioport_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {       int len=0,num,from;
 113         for(num=0;num<IO_BITMAP_SIZE*32;num++)
 114          if(check_bitmap(ioport_registrar,num,1)) {
 115            from=num;
 116            while(check_bitmap(ioport_registrar,num+1,1) 
 117                         && num+1<IO_BITMAP_SIZE*32 )
 118                 num++;
 119            if(from==num) 
 120             len+=sprintf(buf+len,"%04x\n",num);
 121            else
 122             len+=sprintf(buf+len,"%04x-%04x\n",from,num);
 123            if(len>4000) {
 124                 len+=sprintf((buf+len),"4k-Limit reached!\n");
 125                 return len;
 126            }
 127          }
 128         return len;
 129 }
 130 
 131 /*
 132  * this changes the io permissions bitmap in the current task.
 133  */
 134 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
     /* [previous][next][first][last][top][bottom][index][help] */
 135 {
 136         if (from + num <= from)
 137                 return -EINVAL;
 138         if (from + num > IO_BITMAP_SIZE*32)
 139                 return -EINVAL;
 140         if (!suser())
 141                 return -EPERM;
 142 
 143 #ifdef IODEBUG
 144         printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off"));
 145 #endif
 146         set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
 147         return 0;
 148 }
 149 
 150 unsigned int *stack;
 151 
 152 /*
 153  * sys_iopl has to be used when you want to access the IO ports
 154  * beyond the 0x3ff range: to get the full 65536 ports bitmapped
 155  * you'd need 8kB of bitmaps/process, which is a bit excessive.
 156  *
 157  * Here we just change the eflags value on the stack: we allow
 158  * only the super-user to do it. This depends on the stack-layout
 159  * on system-call entry - see also fork() and the signal handling
 160  * code.
 161  */
 162 asmlinkage int sys_iopl(long ebx,long ecx,long edx,
     /* [previous][next][first][last][top][bottom][index][help] */
 163              long esi, long edi, long ebp, long eax, long ds,
 164              long es, long fs, long gs, long orig_eax,
 165              long eip,long cs,long eflags,long esp,long ss)
 166 {
 167         unsigned int level = ebx;
 168 
 169         if (level > 3)
 170                 return -EINVAL;
 171         if (!suser())
 172                 return -EPERM;
 173         *(&eflags) = (eflags & 0xffffcfff) | (level << 12);
 174         return 0;
 175 }
 176 
 177 
 178 void snarf_region(unsigned int from, unsigned int num)
     /* [previous][next][first][last][top][bottom][index][help] */
 179 {
 180         if (from > IO_BITMAP_SIZE*32)
 181                 return;
 182         if (from + num > IO_BITMAP_SIZE*32)
 183                 num = IO_BITMAP_SIZE*32 - from;
 184         set_bitmap(ioport_registrar, from, num, 1);
 185         return;
 186 }
 187 
 188 void release_region(unsigned int from, unsigned int num)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190         if (from > IO_BITMAP_SIZE*32)
 191                 return;
 192         if (from + num > IO_BITMAP_SIZE*32)
 193                 num = IO_BITMAP_SIZE*32 - from;
 194         set_bitmap(ioport_registrar, from, num, 0);
 195         return;
 196 }
 197 
 198 int check_region(unsigned int from, unsigned int num)
     /* [previous][next][first][last][top][bottom][index][help] */
 199 {
 200         if (from > IO_BITMAP_SIZE*32)
 201                 return 0;
 202         if (from + num > IO_BITMAP_SIZE*32)
 203                 num = IO_BITMAP_SIZE*32 - from;
 204         return check_bitmap(ioport_registrar, from, num);
 205 }
 206 
 207 /* Called from init/main.c to reserve IO ports. */
 208 void reserve_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210         int i;
 211 
 212         for (i = 1; i < ints[0]; i += 2)
 213                 snarf_region(ints[i], ints[i+1]);
 214 }

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