ldt_keeper.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:9k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: 4bf5d04bd26ae2f0135df397c2545d6d4e5db8ed $
  3.  *
  4.  * Copyright 1993 Robert J. Amstadt
  5.  * Copyright 1995 Alexandre Julliard
  6.  *
  7.  * Originally distributed under LPGL 2.1 (or later) by the Wine project.
  8.  *
  9.  * Modified for use with MPlayer, detailed CVS changelog at
  10.  * http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/
  11.  *
  12.  * File now distributed as part of VLC media player with no modifications.
  13.  *
  14.  * This program is free software; you can redistribute it and/or modify
  15.  * it under the terms of the GNU General Public License as published by
  16.  * the Free Software Foundation; either version 2 of the License, or
  17.  * (at your option) any later version.
  18.  *
  19.  * This program is distributed in the hope that it will be useful,
  20.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.  * GNU General Public License for more details.
  23.  *
  24.  * You should have received a copy of the GNU General Public License
  25.  * along with this program; if not, write to the Free Software
  26.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  27.  */
  28. /**
  29.  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  30.  * This file MUST be in main library because LDT must
  31.  * be modified before program creates first thread
  32.  * - avifile includes this file from C++ code
  33.  * and initializes it at the start of player!
  34.  * it might sound like a hack and it really is - but
  35.  * as aviplay is deconding video with more than just one
  36.  * thread currently it's necessary to do it this way
  37.  * this might change in the future
  38.  */
  39. /* applied some modification to make make our xine friend more happy */
  40. #include "ldt_keeper.h"
  41. #include <string.h>
  42. #include <stdlib.h>
  43. #include <errno.h>
  44. #include <fcntl.h>
  45. #include <sys/mman.h>
  46. #include <sys/types.h>
  47. #include <stdio.h>
  48. #include <unistd.h>
  49. #ifdef __linux__
  50. #include <asm/unistd.h>
  51. #include <asm/ldt.h>
  52. // 2.5.xx+ calls this user_desc:
  53. #include <linux/version.h>
  54. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,47)
  55. #define modify_ldt_ldt_s user_desc
  56. #endif
  57. /* prototype it here, so we won't depend on kernel headers */
  58. #ifdef  __cplusplus
  59. extern "C" {
  60. #endif
  61. /// declare modify_ldt with the _syscall3 macro for older glibcs
  62. #if defined(__GLIBC__) &&  (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0))
  63. _syscall3( int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount );
  64. #else
  65. int modify_ldt(int func, void *ptr, unsigned long bytecount);
  66. #endif
  67. #ifdef  __cplusplus
  68. }
  69. #endif
  70. #else
  71. #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
  72. #include <machine/segments.h>
  73. #include <machine/sysarch.h>
  74. #endif
  75. #ifdef __svr4__
  76. #include <sys/segment.h>
  77. #include <sys/sysi86.h>
  78. /* solaris x86: add missing prototype for sysi86() */
  79. #ifdef  __cplusplus
  80. extern "C" {
  81. #endif
  82. int sysi86(int, void*);
  83. #ifdef  __cplusplus
  84. }
  85. #endif
  86. #ifndef NUMSYSLDTS             /* SunOS 2.5.1 does not define NUMSYSLDTS */
  87. #define NUMSYSLDTS     6       /* Let's hope the SunOS 5.8 value is OK */
  88. #endif
  89. #define       TEB_SEL_IDX     NUMSYSLDTS
  90. #endif
  91. #define LDT_ENTRIES     8192
  92. #define LDT_ENTRY_SIZE  8
  93. #pragma pack(4)
  94. struct modify_ldt_ldt_s {
  95.         unsigned int  entry_number;
  96.         unsigned long base_addr;
  97.         unsigned int  limit;
  98.         unsigned int  seg_32bit:1;
  99.         unsigned int  contents:2;
  100.         unsigned int  read_exec_only:1;
  101.         unsigned int  limit_in_pages:1;
  102.         unsigned int  seg_not_present:1;
  103.         unsigned int  useable:1;
  104. };
  105. #define MODIFY_LDT_CONTENTS_DATA        0
  106. #define MODIFY_LDT_CONTENTS_STACK       1
  107. #define MODIFY_LDT_CONTENTS_CODE        2
  108. #endif
  109. /* user level (privilege level: 3) ldt (1<<2) segment selector */
  110. #define       LDT_SEL(idx) ((idx) << 3 | 1 << 2 | 3)
  111. /* i got this value from wine sources, it's the first free LDT entry */
  112. #if defined(__FreeBSD__) && defined(LDT_AUTO_ALLOC)
  113. #define       TEB_SEL_IDX     LDT_AUTO_ALLOC
  114. #endif
  115. #ifndef       TEB_SEL_IDX
  116. #define       TEB_SEL_IDX     17
  117. #endif
  118. static unsigned int fs_ldt = TEB_SEL_IDX;
  119. /**
  120.  * here is a small logical problem with Restore for multithreaded programs -
  121.  * in C++ we use static class for this...
  122.  */
  123. #ifdef __cplusplus
  124. extern "C"
  125. #endif
  126. void Setup_FS_Segment(void)
  127. {
  128.     unsigned int ldt_desc = LDT_SEL(fs_ldt);
  129.     __asm__ __volatile__(
  130. "movl %0,%%eax; movw %%ax, %%fs" : : "r" (ldt_desc)
  131. :"eax"
  132.     );
  133. }
  134. /* we don't need this - use modify_ldt instead */
  135. #if 0
  136. #ifdef __linux__
  137. /* XXX: why is this routine from libc redefined here? */
  138. /* NOTE: the redefined version ignores the count param, count is hardcoded as 16 */
  139. static int LDT_Modify( int func, struct modify_ldt_ldt_s *ptr,
  140.        unsigned long count )
  141. {
  142.     int res;
  143. #ifdef __PIC__
  144.     __asm__ __volatile__( "pushl %%ebxnt"
  145.   "movl %2,%%ebxnt"
  146.   "int $0x80nt"
  147.   "popl %%ebx"
  148.   : "=a" (res)
  149.   : "0" (__NR_modify_ldt),
  150.   "r" (func),
  151.   "c" (ptr),
  152.   "d"(16)//sizeof(*ptr) from kernel point of view
  153.   :"esi"     );
  154. #else
  155.     __asm__ __volatile__("int $0x80"
  156.  : "=a" (res)
  157.  : "0" (__NR_modify_ldt),
  158.  "b" (func),
  159.  "c" (ptr),
  160.  "d"(16)
  161.  :"esi");
  162. #endif  /* __PIC__ */
  163.     if (res >= 0) return res;
  164.     errno = -res;
  165.     return -1;
  166. }
  167. #endif
  168. #endif
  169. #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
  170. static void LDT_EntryToBytes( unsigned long *buffer, const struct modify_ldt_ldt_s *content )
  171. {
  172.     *buffer++ = ((content->base_addr & 0x0000ffff) << 16) |
  173. (content->limit & 0x0ffff);
  174.     *buffer = (content->base_addr & 0xff000000) |
  175. ((content->base_addr & 0x00ff0000)>>16) |
  176. (content->limit & 0xf0000) |
  177. (content->contents << 10) |
  178. ((content->read_exec_only == 0) << 9) |
  179. ((content->seg_32bit != 0) << 22) |
  180. ((content->limit_in_pages != 0) << 23) |
  181. 0xf000;
  182. }
  183. #endif
  184. void* fs_seg=0;
  185. ldt_fs_t* Setup_LDT_Keeper(void)
  186. {
  187.     struct modify_ldt_ldt_s array;
  188.     int ret;
  189.     ldt_fs_t* ldt_fs = (ldt_fs_t*) malloc(sizeof(ldt_fs_t));
  190.     if (!ldt_fs)
  191. return NULL;
  192.     ldt_fs->fd = open("/dev/zero", O_RDWR);
  193.     if(ldt_fs->fd<0){
  194.         perror( "Cannot open /dev/zero for READ+WRITE. Check permissions! error: ");
  195.         free(ldt_fs);
  196. return NULL;
  197.     }
  198.     fs_seg=
  199.     ldt_fs->fs_seg = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE,
  200.   ldt_fs->fd, 0);
  201.     if (ldt_fs->fs_seg == (void*)-1)
  202.     {
  203. perror("ERROR: Couldn't allocate memory for fs segment");
  204.         close(ldt_fs->fd);
  205.         free(ldt_fs);
  206. return NULL;
  207.     }
  208.     *(void**)((char*)ldt_fs->fs_seg+0x18) = ldt_fs->fs_seg;
  209.     memset(&array, 0, sizeof(array));
  210.     array.base_addr=(int)ldt_fs->fs_seg;
  211.     array.entry_number=TEB_SEL_IDX;
  212.     array.limit=array.base_addr+getpagesize()-1;
  213.     array.seg_32bit=1;
  214.     array.read_exec_only=0;
  215.     array.seg_not_present=0;
  216.     array.contents=MODIFY_LDT_CONTENTS_DATA;
  217.     array.limit_in_pages=0;
  218. #ifdef __linux__
  219.     //ret=LDT_Modify(0x1, &array, sizeof(struct modify_ldt_ldt_s));
  220.     ret=modify_ldt(0x1, &array, sizeof(struct modify_ldt_ldt_s));
  221.     if(ret<0)
  222.     {
  223. perror("install_fs");
  224. printf("Couldn't install fs segment, expect segfaultn");
  225.     }
  226. #endif /*linux*/
  227. #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
  228.     {
  229.         unsigned long d[2];
  230.         LDT_EntryToBytes( d, &array );
  231. #if defined(__FreeBSD__) && defined(LDT_AUTO_ALLOC)
  232.         ret = i386_set_ldt(LDT_AUTO_ALLOC, (union descriptor *)d, 1);
  233.         array.entry_number = ret;
  234.         fs_ldt = ret;
  235. #else
  236.         ret = i386_set_ldt(array.entry_number, (union descriptor *)d, 1);
  237. #endif
  238.         if (ret < 0)
  239.         {
  240.             perror("install_fs");
  241.     printf("Couldn't install fs segment, expect segfaultn");
  242.             printf("Did you reconfigure the kernel with "options USER_LDT"?n");
  243.         }
  244.     }
  245. #endif  /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__ */
  246. #if defined(__svr4__)
  247.     {
  248. struct ssd ssd;
  249. ssd.sel = LDT_SEL(TEB_SEL_IDX);
  250. ssd.bo = array.base_addr;
  251. ssd.ls = array.limit - array.base_addr;
  252. ssd.acc1 = ((array.read_exec_only == 0) << 1) |
  253.     (array.contents << 2) |
  254.     0xf0;   /* P(resent) | DPL3 | S */
  255. ssd.acc2 = 0x4;   /* byte limit, 32-bit segment */
  256. if (sysi86(SI86DSCR, &ssd) < 0) {
  257.     perror("sysi86(SI86DSCR)");
  258.     printf("Couldn't install fs segment, expect segfaultn");
  259. }
  260.     }
  261. #endif
  262.     Setup_FS_Segment();
  263.     ldt_fs->prev_struct = (char*)malloc(sizeof(char) * 8);
  264.     *(void**)array.base_addr = ldt_fs->prev_struct;
  265.     return ldt_fs;
  266. }
  267. void Restore_LDT_Keeper(ldt_fs_t* ldt_fs)
  268. {
  269.     if (ldt_fs == NULL || ldt_fs->fs_seg == NULL)
  270. return;
  271.     free(ldt_fs->prev_struct);
  272.     munmap((char*)ldt_fs->fs_seg, getpagesize());
  273.     ldt_fs->fs_seg = 0;
  274.     close(ldt_fs->fd);
  275.     free(ldt_fs);
  276. }