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

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