Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

ldt_keeper.c

00001 
00013 /* applied some modification to make make our xine friend more happy */
00014 
00015 /*
00016  * Modified for use with MPlayer, detailed CVS changelog at
00017  * http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/
00018  * $Id: ldt_keeper.c 11593 2005-06-28 18:02:01Z courmisch $
00019  */
00020 
00021 #include "ldt_keeper.h"
00022 
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include <errno.h>
00026 #include <fcntl.h>
00027 #include <sys/mman.h>
00028 #include <sys/types.h>
00029 #include <stdio.h>
00030 #include <unistd.h>
00031 #ifdef __linux__
00032 #include <asm/unistd.h>
00033 #include <asm/ldt.h>
00034 // 2.5.xx+ calls this user_desc:
00035 #include <linux/version.h>
00036 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,47)
00037 #define modify_ldt_ldt_s user_desc
00038 #endif
00039 /* prototype it here, so we won't depend on kernel headers */
00040 #ifdef  __cplusplus
00041 extern "C" {
00042 #endif
00043 
00044 #if defined(__GLIBC__) &&  (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0))
00045 _syscall3( int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount );
00046 #else
00047 int modify_ldt(int func, void *ptr, unsigned long bytecount);
00048 #endif
00049 #ifdef  __cplusplus
00050 }
00051 #endif
00052 #else
00053 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
00054 #include <machine/segments.h>
00055 #include <machine/sysarch.h>
00056 #endif
00057 
00058 #ifdef __svr4__
00059 #include <sys/segment.h>
00060 #include <sys/sysi86.h>
00061 
00062 /* solaris x86: add missing prototype for sysi86() */
00063 #ifdef  __cplusplus
00064 extern "C" {
00065 #endif
00066 int sysi86(int, void*);
00067 #ifdef  __cplusplus
00068 }
00069 #endif
00070 
00071 #ifndef NUMSYSLDTS             /* SunOS 2.5.1 does not define NUMSYSLDTS */
00072 #define NUMSYSLDTS     6       /* Let's hope the SunOS 5.8 value is OK */
00073 #endif
00074 
00075 #define       TEB_SEL_IDX     NUMSYSLDTS
00076 #endif
00077 
00078 #define LDT_ENTRIES     8192
00079 #define LDT_ENTRY_SIZE  8
00080 #pragma pack(4)
00081 struct modify_ldt_ldt_s {
00082         unsigned int  entry_number;
00083         unsigned long base_addr;
00084         unsigned int  limit;
00085         unsigned int  seg_32bit:1;
00086         unsigned int  contents:2;
00087         unsigned int  read_exec_only:1;
00088         unsigned int  limit_in_pages:1;
00089         unsigned int  seg_not_present:1;
00090         unsigned int  useable:1;
00091 };
00092 
00093 #define MODIFY_LDT_CONTENTS_DATA        0
00094 #define MODIFY_LDT_CONTENTS_STACK       1
00095 #define MODIFY_LDT_CONTENTS_CODE        2
00096 #endif
00097 
00098 
00099 /* user level (privilege level: 3) ldt (1<<2) segment selector */
00100 #define       LDT_SEL(idx) ((idx) << 3 | 1 << 2 | 3)
00101 
00102 /* i got this value from wine sources, it's the first free LDT entry */
00103 #if defined(__FreeBSD__) && defined(LDT_AUTO_ALLOC)
00104 #define       TEB_SEL_IDX     LDT_AUTO_ALLOC
00105 #endif
00106 
00107 #ifndef       TEB_SEL_IDX
00108 #define       TEB_SEL_IDX     17
00109 #endif
00110 
00111 static unsigned int fs_ldt = TEB_SEL_IDX;
00112 
00113 
00119 #ifdef __cplusplus
00120 extern "C"
00121 #endif
00122 void Setup_FS_Segment(void)
00123 {
00124     unsigned int ldt_desc = LDT_SEL(fs_ldt);
00125 
00126     __asm__ __volatile__(
00127         "movl %0,%%eax; movw %%ax, %%fs" : : "r" (ldt_desc)
00128         :"eax"
00129     );
00130 }
00131 
00132 /* we don't need this - use modify_ldt instead */
00133 #if 0
00134 #ifdef __linux__
00135 /* XXX: why is this routine from libc redefined here? */
00136 /* NOTE: the redefined version ignores the count param, count is hardcoded as 16 */
00137 static int LDT_Modify( int func, struct modify_ldt_ldt_s *ptr,
00138                        unsigned long count )
00139 {
00140     int res;
00141 #ifdef __PIC__
00142     __asm__ __volatile__( "pushl %%ebx\n\t"
00143                           "movl %2,%%ebx\n\t"
00144                           "int $0x80\n\t"
00145                           "popl %%ebx"
00146                           : "=a" (res)
00147                           : "0" (__NR_modify_ldt),
00148                           "r" (func),
00149                           "c" (ptr),
00150                           "d"(16)//sizeof(*ptr) from kernel point of view
00151                           :"esi"     );
00152 #else
00153     __asm__ __volatile__("int $0x80"
00154                          : "=a" (res)
00155                          : "0" (__NR_modify_ldt),
00156                          "b" (func),
00157                          "c" (ptr),
00158                          "d"(16)
00159                          :"esi");
00160 #endif  /* __PIC__ */
00161     if (res >= 0) return res;
00162     errno = -res;
00163     return -1;
00164 }
00165 #endif
00166 #endif
00167 
00168 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
00169 static void LDT_EntryToBytes( unsigned long *buffer, const struct modify_ldt_ldt_s *content )
00170 {
00171     *buffer++ = ((content->base_addr & 0x0000ffff) << 16) |
00172         (content->limit & 0x0ffff);
00173     *buffer = (content->base_addr & 0xff000000) |
00174         ((content->base_addr & 0x00ff0000)>>16) |
00175         (content->limit & 0xf0000) |
00176         (content->contents << 10) |
00177         ((content->read_exec_only == 0) << 9) |
00178         ((content->seg_32bit != 0) << 22) |
00179         ((content->limit_in_pages != 0) << 23) |
00180         0xf000;
00181 }
00182 #endif
00183 
00184 void* fs_seg=0;
00185 
00186 ldt_fs_t* Setup_LDT_Keeper(void)
00187 {
00188     struct modify_ldt_ldt_s array;
00189     int ret;
00190     ldt_fs_t* ldt_fs = (ldt_fs_t*) malloc(sizeof(ldt_fs_t));
00191 
00192     if (!ldt_fs)
00193         return NULL;
00194 
00195     ldt_fs->fd = open("/dev/zero", O_RDWR);
00196     if(ldt_fs->fd<0){
00197         perror( "Cannot open /dev/zero for READ+WRITE. Check permissions! error: ");
00198         return NULL;
00199     }
00200     fs_seg=
00201     ldt_fs->fs_seg = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE,
00202                           ldt_fs->fd, 0);
00203     if (ldt_fs->fs_seg == (void*)-1)
00204     {
00205         perror("ERROR: Couldn't allocate memory for fs segment");
00206         close(ldt_fs->fd);
00207         free(ldt_fs);
00208         return NULL;
00209     }
00210     *(void**)((char*)ldt_fs->fs_seg+0x18) = ldt_fs->fs_seg;
00211     memset(&array, 0, sizeof(array));
00212     array.base_addr=(int)ldt_fs->fs_seg;
00213     array.entry_number=TEB_SEL_IDX;
00214     array.limit=array.base_addr+getpagesize()-1;
00215     array.seg_32bit=1;
00216     array.read_exec_only=0;
00217     array.seg_not_present=0;
00218     array.contents=MODIFY_LDT_CONTENTS_DATA;
00219     array.limit_in_pages=0;
00220 #ifdef __linux__
00221     //ret=LDT_Modify(0x1, &array, sizeof(struct modify_ldt_ldt_s));
00222     ret=modify_ldt(0x1, &array, sizeof(struct modify_ldt_ldt_s));
00223     if(ret<0)
00224     {
00225         perror("install_fs");
00226         printf("Couldn't install fs segment, expect segfault\n");
00227     }
00228 #endif /*linux*/
00229 
00230 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
00231     {
00232         unsigned long d[2];
00233 
00234         LDT_EntryToBytes( d, &array );
00235 #if defined(__FreeBSD__) && defined(LDT_AUTO_ALLOC)
00236         ret = i386_set_ldt(LDT_AUTO_ALLOC, (union descriptor *)d, 1);
00237         array.entry_number = ret;
00238         fs_ldt = ret;
00239 #else
00240         ret = i386_set_ldt(array.entry_number, (union descriptor *)d, 1);
00241 #endif
00242         if (ret < 0)
00243         {
00244             perror("install_fs");
00245             printf("Couldn't install fs segment, expect segfault\n");
00246             printf("Did you reconfigure the kernel with \"options USER_LDT\"?\n");
00247         }
00248     }
00249 #endif  /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__ */
00250 
00251 #if defined(__svr4__)
00252     {
00253         struct ssd ssd;
00254         ssd.sel = LDT_SEL(TEB_SEL_IDX);
00255         ssd.bo = array.base_addr;
00256         ssd.ls = array.limit - array.base_addr;
00257         ssd.acc1 = ((array.read_exec_only == 0) << 1) |
00258             (array.contents << 2) |
00259             0xf0;   /* P(resent) | DPL3 | S */
00260         ssd.acc2 = 0x4;   /* byte limit, 32-bit segment */
00261         if (sysi86(SI86DSCR, &ssd) < 0) {
00262             perror("sysi86(SI86DSCR)");
00263             printf("Couldn't install fs segment, expect segfault\n");
00264         }
00265     }
00266 #endif
00267 
00268     Setup_FS_Segment();
00269 
00270     ldt_fs->prev_struct = (char*)malloc(sizeof(char) * 8);
00271     *(void**)array.base_addr = ldt_fs->prev_struct;
00272 
00273     return ldt_fs;
00274 }
00275 
00276 void Restore_LDT_Keeper(ldt_fs_t* ldt_fs)
00277 {
00278     if (ldt_fs == NULL || ldt_fs->fs_seg == 0)
00279         return;
00280     if (ldt_fs->prev_struct)
00281         free(ldt_fs->prev_struct);
00282     munmap((char*)ldt_fs->fs_seg, getpagesize());
00283     ldt_fs->fs_seg = 0;
00284     close(ldt_fs->fd);
00285     free(ldt_fs);
00286 }

Generated on Tue Dec 20 10:14:20 2005 for vlc-0.8.4a by  doxygen 1.4.2