root/arch/i386/kernel/ldt.c

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

DEFINITIONS

This source file includes following definitions.
  1. read_ldt
  2. write_ldt
  3. sys_modify_ldt

   1 /*
   2  * linux/kernel/ldt.c
   3  *
   4  * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
   5  */
   6 
   7 #include <linux/errno.h>
   8 #include <linux/sched.h>
   9 #include <linux/string.h>
  10 #include <asm/segment.h>
  11 #include <asm/system.h>
  12 #include <linux/ldt.h>
  13 
  14 static int read_ldt(void * ptr, unsigned long bytecount)
     /* [previous][next][first][last][top][bottom][index][help] */
  15 {
  16         int error;
  17         void * address = current->ldt;
  18         unsigned long size;
  19 
  20         if (!ptr)
  21                 return -EINVAL;
  22         size = LDT_ENTRIES*LDT_ENTRY_SIZE;
  23         if (!address) {
  24                 address = &default_ldt;
  25                 size = sizeof(default_ldt);
  26         }
  27         if (size > bytecount)
  28                 size = bytecount;
  29         error = verify_area(VERIFY_WRITE, ptr, size);
  30         if (error)
  31                 return error;
  32         memcpy_tofs(ptr, address, size);
  33         return size;
  34 }
  35 
  36 static int write_ldt(void * ptr, unsigned long bytecount)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38         struct modify_ldt_ldt_s ldt_info;
  39         unsigned long *lp;
  40         unsigned long base, limit;
  41         int error, i;
  42 
  43         if (bytecount != sizeof(ldt_info))
  44                 return -EINVAL;
  45         error = verify_area(VERIFY_READ, ptr, sizeof(ldt_info));
  46         if (error)
  47                 return error;
  48 
  49         memcpy_fromfs(&ldt_info, ptr, sizeof(ldt_info));
  50 
  51         if (ldt_info.contents == 3 || ldt_info.entry_number >= LDT_ENTRIES)
  52                 return -EINVAL;
  53 
  54         limit = ldt_info.limit;
  55         base = ldt_info.base_addr;
  56         if (ldt_info.limit_in_pages)
  57                 limit *= PAGE_SIZE;
  58 
  59         limit += base;
  60         if (limit < base || limit >= 0xC0000000)
  61                 return -EINVAL;
  62 
  63         if (!current->ldt) {
  64                 for (i=1 ; i<NR_TASKS ; i++) {
  65                         if (task[i] == current) {
  66                                 if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
  67                                         return -ENOMEM;
  68                                 set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
  69                                 load_ldt(i);
  70                         }
  71                 }
  72         }
  73         
  74         lp = (unsigned long *) &current->ldt[ldt_info.entry_number];
  75         /* Allow LDTs to be cleared by the user. */
  76         if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
  77                 *lp = 0;
  78                 *(lp+1) = 0;
  79                 return 0;
  80         }
  81         *lp = ((ldt_info.base_addr & 0x0000ffff) << 16) |
  82                   (ldt_info.limit & 0x0ffff);
  83         *(lp+1) = (ldt_info.base_addr & 0xff000000) |
  84                   ((ldt_info.base_addr & 0x00ff0000)>>16) |
  85                   (ldt_info.limit & 0xf0000) |
  86                   (ldt_info.contents << 10) |
  87                   ((ldt_info.read_exec_only ^ 1) << 9) |
  88                   (ldt_info.seg_32bit << 22) |
  89                   (ldt_info.limit_in_pages << 23) |
  90                   ((ldt_info.seg_not_present ^1) << 15) |
  91                   0x7000;
  92         return 0;
  93 }
  94 
  95 asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97         if (func == 0)
  98                 return read_ldt(ptr, bytecount);
  99         if (func == 1)
 100                 return write_ldt(ptr, bytecount);
 101         return -ENOSYS;
 102 }

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