root/arch/i386/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. do_snarf_region
  9. register_iomem
  10. snarf_region
  11. do_release_region
  12. release_region
  13. check_region
  14. 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 #define IOPORTNAMES_NUM 32
  16 #define IOPORTNAMES_LEN 26
  17 struct { int from;
  18          int num;       
  19          int flags;
  20          char name[IOPORTNAMES_LEN];
  21         } ioportnames[IOPORTNAMES_NUM];
  22 
  23 #define _IODEBUG
  24 
  25 #ifdef IODEBUG
  26 static char * ios(unsigned long l)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28         static char str[33] = { '\0' };
  29         int i;
  30         unsigned long mask;
  31 
  32         for (i = 0, mask = 0x80000000; i < 32; ++i, mask >>= 1)
  33                 str[i] = (l & mask) ? '1' : '0';
  34         return str;
  35 }
  36 
  37 static void dump_io_bitmap(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  38 {
  39         int i, j;
  40         int numl = sizeof(current->tss.io_bitmap) >> 2;
  41 
  42         for (i = j = 0; j < numl; ++i)
  43         {
  44                 printk("%4d [%3x]: ", 64*i, 64*i);
  45                 printk("%s ", ios(current->tss.io_bitmap[j++]));
  46                 if (j < numl)
  47                         printk("%s", ios(current->tss.io_bitmap[j++]));
  48                 printk("\n");
  49         }
  50 }
  51 #endif
  52 
  53 /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
  54 asmlinkage void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56         int mask;
  57         unsigned long *bitmap_base = bitmap + (base >> 5);
  58         unsigned short low_index = base & 0x1f;
  59         int length = low_index + extent;
  60 
  61         if (low_index != 0) {
  62                 mask = (~0 << low_index);
  63                 if (length < 32)
  64                                 mask &= ~(~0 << length);
  65                 if (new_value)
  66                         *bitmap_base++ |= mask;
  67                 else
  68                         *bitmap_base++ &= ~mask;
  69                 length -= 32;
  70         }
  71 
  72         mask = (new_value ? ~0 : 0);
  73         while (length >= 32) {
  74                 *bitmap_base++ = mask;
  75                 length -= 32;
  76         }
  77 
  78         if (length > 0) {
  79                 mask = ~(~0 << length);
  80                 if (new_value)
  81                         *bitmap_base++ |= mask;
  82                 else
  83                         *bitmap_base++ &= ~mask;
  84         }
  85 }
  86 
  87 /* Check for set bits in BITMAP starting at BASE, going to EXTENT. */
  88 asmlinkage int check_bitmap(unsigned long *bitmap, short base, short extent)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90         int mask;
  91         unsigned long *bitmap_base = bitmap + (base >> 5);
  92         unsigned short low_index = base & 0x1f;
  93         int length = low_index + extent;
  94 
  95         if (low_index != 0) {
  96                 mask = (~0 << low_index);
  97                 if (length < 32)
  98                                 mask &= ~(~0 << length);
  99                 if (*bitmap_base++ & mask)
 100                         return 1;
 101                 length -= 32;
 102         }
 103         while (length >= 32) {
 104                 if (*bitmap_base++ != 0)
 105                         return 1;
 106                 length -= 32;
 107         }
 108 
 109         if (length > 0) {
 110                 mask = ~(~0 << length);
 111                 if (*bitmap_base++ & mask)
 112                         return 1;
 113         }
 114         return 0;
 115 }
 116 
 117 /*
 118  * This generates the report for /proc/ioports
 119  */
 120 int get_ioport_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {       int i=0,len=0;
 122         while(i<IOPORTNAMES_LEN && len<4000)
 123         {       if(ioportnames[i].flags)
 124                         len+=sprintf(buf+len,"%04x-%04x : %s\n",
 125                                 ioportnames[i].from,
 126                                 ioportnames[i].from+ioportnames[i].num-1,
 127                                 ioportnames[i].name);
 128                 i++;
 129         }
 130         if(len>=4000) 
 131                 len+=sprintf(buf+len,"4k-Limit reached!\n");
 132         return len;
 133 }
 134 
 135 /*
 136  * this changes the io permissions bitmap in the current task.
 137  */
 138 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140         if (from + num <= from)
 141                 return -EINVAL;
 142         if (from + num > IO_BITMAP_SIZE*32)
 143                 return -EINVAL;
 144         if (!suser())
 145                 return -EPERM;
 146 
 147 #ifdef IODEBUG
 148         printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off"));
 149 #endif
 150         set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
 151         return 0;
 152 }
 153 
 154 unsigned int *stack;
 155 
 156 /*
 157  * sys_iopl has to be used when you want to access the IO ports
 158  * beyond the 0x3ff range: to get the full 65536 ports bitmapped
 159  * you'd need 8kB of bitmaps/process, which is a bit excessive.
 160  *
 161  * Here we just change the eflags value on the stack: we allow
 162  * only the super-user to do it. This depends on the stack-layout
 163  * on system-call entry - see also fork() and the signal handling
 164  * code.
 165  */
 166 asmlinkage int sys_iopl(long ebx,long ecx,long edx,
     /* [previous][next][first][last][top][bottom][index][help] */
 167              long esi, long edi, long ebp, long eax, long ds,
 168              long es, long fs, long gs, long orig_eax,
 169              long eip,long cs,long eflags,long esp,long ss)
 170 {
 171         unsigned int level = ebx;
 172 
 173         if (level > 3)
 174                 return -EINVAL;
 175         if (!suser())
 176                 return -EPERM;
 177         *(&eflags) = (eflags & 0xffffcfff) | (level << 12);
 178         return 0;
 179 }
 180 
 181 /*
 182  * This is the 'old' snarfing worker function
 183  */
 184 void do_snarf_region(unsigned int from, unsigned int num)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186         if (from > IO_BITMAP_SIZE*32)
 187                 return;
 188         if (from + num > IO_BITMAP_SIZE*32)
 189                 num = IO_BITMAP_SIZE*32 - from;
 190         set_bitmap(ioport_registrar, from, num, 1);
 191         return;
 192 }
 193 
 194 /*
 195  * Call this from the device driver to register the ioport region.
 196  */
 197 void register_iomem(unsigned int from, unsigned int num, char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 198 {       
 199         int i=0;
 200         while(ioportnames[i].flags && i<IOPORTNAMES_NUM)
 201          i++;
 202         if(i==IOPORTNAMES_NUM)
 203                 printk("warning:ioportname-table is full");
 204         else
 205         {       
 206                 strncpy(ioportnames[i].name,name,IOPORTNAMES_LEN);
 207                 ioportnames[i].name[IOPORTNAMES_LEN-1]=(char)0;
 208                 ioportnames[i].from=from;
 209                 ioportnames[i].num=num;
 210                 ioportnames[i].flags=1;
 211         }
 212         do_snarf_region(from,num);
 213 }
 214 
 215 /*
 216  * This is for compatibilty with older drivers.
 217  * It can be removed when all driver call the new function.
 218  */
 219 void snarf_region(unsigned int from, unsigned int num)
     /* [previous][next][first][last][top][bottom][index][help] */
 220 {       register_iomem(from,num,"No name given.");
 221 }
 222 
 223 /*
 224  * The worker for releasing
 225  */
 226 void do_release_region(unsigned int from, unsigned int num)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228         if (from > IO_BITMAP_SIZE*32)
 229                 return;
 230         if (from + num > IO_BITMAP_SIZE*32)
 231                 num = IO_BITMAP_SIZE*32 - from;
 232         set_bitmap(ioport_registrar, from, num, 0);
 233         return;
 234 }
 235 
 236 /* 
 237  * Call this when the device driver is unloaded
 238  */
 239 void release_region(unsigned int from, unsigned int num)
     /* [previous][next][first][last][top][bottom][index][help] */
 240 {       int i=0;
 241         while(i<IOPORTNAMES_NUM)
 242         {       if(ioportnames[i].from==from && ioportnames[i].num==num)
 243                         ioportnames[i].flags=0; 
 244                 i++;
 245         }
 246         do_release_region(from,num);
 247 }
 248 
 249 /*
 250  * Call this to check the ioport region before probing
 251  */
 252 int check_region(unsigned int from, unsigned int num)
     /* [previous][next][first][last][top][bottom][index][help] */
 253 {
 254         if (from > IO_BITMAP_SIZE*32)
 255                 return 0;
 256         if (from + num > IO_BITMAP_SIZE*32)
 257                 num = IO_BITMAP_SIZE*32 - from;
 258         return check_bitmap(ioport_registrar, from, num);
 259 }
 260 
 261 /* Called from init/main.c to reserve IO ports. */
 262 void reserve_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
 263 {
 264         int i;
 265 
 266         for (i = 1; i < ints[0]; i += 2)
 267                 register_iomem(ints[i], ints[i+1],"reserved");
 268 }

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