home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / kernel / ldt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-15  |  2.4 KB  |  103 lines

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