Mercurial > mplayer.hg
annotate loader/ldt_keeper.c @ 15533:ddf15d233d58
Do not switch to audio tracks whose codec private data differs from the main audio track's as this will most likely result in messed up audio output. Patch by Michael Behrisch <list () behrisch ! de>
author | mosu |
---|---|
date | Sat, 21 May 2005 06:50:08 +0000 |
parents | f5537cc95b02 |
children | 3758536dcef3 |
rev | line source |
---|---|
2067 | 1 /** |
2 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
3 * This file MUST be in main library because LDT must | |
4 * be modified before program creates first thread | |
5 * - avifile includes this file from C++ code | |
6 * and initializes it at the start of player! | |
7386 | 7 * it might sound like a hack and it really is - but |
8 * as aviplay is deconding video with more than just one | |
9 * thread currently it's necessary to do it this way | |
10 * this might change in the future | |
2067 | 11 */ |
12 | |
7386 | 13 /* applied some modification to make make our xine friend more happy */ |
15166
f5537cc95b02
Mark modified imported files as such to comply with GPL ¡ø2a.
diego
parents:
14537
diff
changeset
|
14 |
f5537cc95b02
Mark modified imported files as such to comply with GPL ¡ø2a.
diego
parents:
14537
diff
changeset
|
15 /* |
f5537cc95b02
Mark modified imported files as such to comply with GPL ¡ø2a.
diego
parents:
14537
diff
changeset
|
16 * Modified for use with MPlayer, detailed CVS changelog at |
f5537cc95b02
Mark modified imported files as such to comply with GPL ¡ø2a.
diego
parents:
14537
diff
changeset
|
17 * http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ |
f5537cc95b02
Mark modified imported files as such to comply with GPL ¡ø2a.
diego
parents:
14537
diff
changeset
|
18 * $Id$ |
f5537cc95b02
Mark modified imported files as such to comply with GPL ¡ø2a.
diego
parents:
14537
diff
changeset
|
19 */ |
f5537cc95b02
Mark modified imported files as such to comply with GPL ¡ø2a.
diego
parents:
14537
diff
changeset
|
20 |
2139 | 21 #include "ldt_keeper.h" |
22 | |
2067 | 23 #include <string.h> |
24 #include <stdlib.h> | |
25 #include <errno.h> | |
26 #include <fcntl.h> | |
27 #include <sys/mman.h> | |
28 #include <sys/types.h> | |
29 #include <stdio.h> | |
30 #include <unistd.h> | |
31 #ifdef __linux__ | |
32 #include <asm/unistd.h> | |
33 #include <asm/ldt.h> | |
8213 | 34 // 2.5.xx+ calls this user_desc: |
35 #include <linux/version.h> | |
36 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,47) | |
37 #define modify_ldt_ldt_s user_desc | |
38 #endif | |
7386 | 39 /* prototype it here, so we won't depend on kernel headers */ |
40 #ifdef __cplusplus | |
41 extern "C" { | |
42 #endif | |
13351
698fe63084d3
declare modify_ldt with syscall3 macro for older glibcs patch by Mikulas Patocka <mikulas at artax.karlin.mff.cuni.cz>
faust3
parents:
10821
diff
changeset
|
43 /// declare modify_ldt with the _syscall3 macro for older glibcs |
13361 | 44 #if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)) |
13351
698fe63084d3
declare modify_ldt with syscall3 macro for older glibcs patch by Mikulas Patocka <mikulas at artax.karlin.mff.cuni.cz>
faust3
parents:
10821
diff
changeset
|
45 _syscall3( int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount ); |
698fe63084d3
declare modify_ldt with syscall3 macro for older glibcs patch by Mikulas Patocka <mikulas at artax.karlin.mff.cuni.cz>
faust3
parents:
10821
diff
changeset
|
46 #else |
7386 | 47 int modify_ldt(int func, void *ptr, unsigned long bytecount); |
13351
698fe63084d3
declare modify_ldt with syscall3 macro for older glibcs patch by Mikulas Patocka <mikulas at artax.karlin.mff.cuni.cz>
faust3
parents:
10821
diff
changeset
|
48 #endif |
7386 | 49 #ifdef __cplusplus |
50 } | |
51 #endif | |
2067 | 52 #else |
53 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) | |
5872 | 54 #include <machine/segments.h> |
2067 | 55 #include <machine/sysarch.h> |
56 #endif | |
57 | |
58 #ifdef __svr4__ | |
59 #include <sys/segment.h> | |
60 #include <sys/sysi86.h> | |
61 | |
62 /* solaris x86: add missing prototype for sysi86() */ | |
63 #ifdef __cplusplus | |
64 extern "C" { | |
65 #endif | |
7386 | 66 int sysi86(int, void*); |
2067 | 67 #ifdef __cplusplus |
68 } | |
69 #endif | |
70 | |
2139 | 71 #ifndef NUMSYSLDTS /* SunOS 2.5.1 does not define NUMSYSLDTS */ |
72 #define NUMSYSLDTS 6 /* Let's hope the SunOS 5.8 value is OK */ | |
2067 | 73 #endif |
74 | |
75 #define TEB_SEL_IDX NUMSYSLDTS | |
76 #endif | |
77 | |
78 #define LDT_ENTRIES 8192 | |
79 #define LDT_ENTRY_SIZE 8 | |
80 #pragma pack(4) | |
81 struct modify_ldt_ldt_s { | |
82 unsigned int entry_number; | |
83 unsigned long base_addr; | |
84 unsigned int limit; | |
85 unsigned int seg_32bit:1; | |
86 unsigned int contents:2; | |
87 unsigned int read_exec_only:1; | |
88 unsigned int limit_in_pages:1; | |
89 unsigned int seg_not_present:1; | |
90 unsigned int useable:1; | |
91 }; | |
92 | |
93 #define MODIFY_LDT_CONTENTS_DATA 0 | |
94 #define MODIFY_LDT_CONTENTS_STACK 1 | |
95 #define MODIFY_LDT_CONTENTS_CODE 2 | |
96 #endif | |
97 | |
98 | |
99 /* user level (privilege level: 3) ldt (1<<2) segment selector */ | |
100 #define LDT_SEL(idx) ((idx) << 3 | 1 << 2 | 3) | |
101 | |
7386 | 102 /* i got this value from wine sources, it's the first free LDT entry */ |
10821
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
103 #if defined(__FreeBSD__) && defined(LDT_AUTO_ALLOC) |
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
104 #define TEB_SEL_IDX LDT_AUTO_ALLOC |
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
105 #endif |
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
106 |
2067 | 107 #ifndef TEB_SEL_IDX |
7386 | 108 #define TEB_SEL_IDX 17 |
2067 | 109 #endif |
7386 | 110 |
10821
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
111 static unsigned int fs_ldt = TEB_SEL_IDX; |
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
112 |
2067 | 113 |
114 /** | |
115 * here is a small logical problem with Restore for multithreaded programs - | |
116 * in C++ we use static class for this... | |
117 */ | |
118 | |
119 #ifdef __cplusplus | |
120 extern "C" | |
121 #endif | |
122 void Setup_FS_Segment(void) | |
123 { | |
10821
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
124 unsigned int ldt_desc = LDT_SEL(fs_ldt); |
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
125 |
2067 | 126 __asm__ __volatile__( |
10821
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
127 "movl %0,%%eax; movw %%ax, %%fs" : : "r" (ldt_desc) |
14212
540903a59fc0
add missing registers in clobber list, fixes bug #169
reimar
parents:
13361
diff
changeset
|
128 :"eax" |
2067 | 129 ); |
130 } | |
131 | |
7386 | 132 /* we don't need this - use modify_ldt instead */ |
133 #if 0 | |
2067 | 134 #ifdef __linux__ |
135 /* XXX: why is this routine from libc redefined here? */ | |
136 /* NOTE: the redefined version ignores the count param, count is hardcoded as 16 */ | |
137 static int LDT_Modify( int func, struct modify_ldt_ldt_s *ptr, | |
138 unsigned long count ) | |
139 { | |
140 int res; | |
141 #ifdef __PIC__ | |
142 __asm__ __volatile__( "pushl %%ebx\n\t" | |
143 "movl %2,%%ebx\n\t" | |
144 "int $0x80\n\t" | |
145 "popl %%ebx" | |
146 : "=a" (res) | |
147 : "0" (__NR_modify_ldt), | |
148 "r" (func), | |
149 "c" (ptr), | |
150 "d"(16)//sizeof(*ptr) from kernel point of view | |
151 :"esi" ); | |
152 #else | |
153 __asm__ __volatile__("int $0x80" | |
154 : "=a" (res) | |
155 : "0" (__NR_modify_ldt), | |
156 "b" (func), | |
157 "c" (ptr), | |
158 "d"(16) | |
159 :"esi"); | |
160 #endif /* __PIC__ */ | |
161 if (res >= 0) return res; | |
162 errno = -res; | |
163 return -1; | |
164 } | |
165 #endif | |
7386 | 166 #endif |
2067 | 167 |
168 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) | |
169 static void LDT_EntryToBytes( unsigned long *buffer, const struct modify_ldt_ldt_s *content ) | |
170 { | |
171 *buffer++ = ((content->base_addr & 0x0000ffff) << 16) | | |
172 (content->limit & 0x0ffff); | |
173 *buffer = (content->base_addr & 0xff000000) | | |
174 ((content->base_addr & 0x00ff0000)>>16) | | |
175 (content->limit & 0xf0000) | | |
176 (content->contents << 10) | | |
177 ((content->read_exec_only == 0) << 9) | | |
178 ((content->seg_32bit != 0) << 22) | | |
179 ((content->limit_in_pages != 0) << 23) | | |
180 0xf000; | |
181 } | |
182 #endif | |
183 | |
8223 | 184 void* fs_seg=0; |
7386 | 185 |
186 ldt_fs_t* Setup_LDT_Keeper(void) | |
2067 | 187 { |
188 struct modify_ldt_ldt_s array; | |
189 int ret; | |
7386 | 190 ldt_fs_t* ldt_fs = (ldt_fs_t*) malloc(sizeof(ldt_fs_t)); |
2067 | 191 |
7386 | 192 if (!ldt_fs) |
193 return NULL; | |
2067 | 194 |
7386 | 195 ldt_fs->fd = open("/dev/zero", O_RDWR); |
196 if(ldt_fs->fd<0){ | |
197 perror( "Cannot open /dev/zero for READ+WRITE. Check permissions! error: "); | |
198 return NULL; | |
3775 | 199 } |
8223 | 200 fs_seg= |
7386 | 201 ldt_fs->fs_seg = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE, |
202 ldt_fs->fd, 0); | |
203 if (ldt_fs->fs_seg == (void*)-1) | |
2067 | 204 { |
205 perror("ERROR: Couldn't allocate memory for fs segment"); | |
7386 | 206 close(ldt_fs->fd); |
207 free(ldt_fs); | |
208 return NULL; | |
2067 | 209 } |
7386 | 210 *(void**)((char*)ldt_fs->fs_seg+0x18) = ldt_fs->fs_seg; |
14537 | 211 memset(&array, 0, sizeof(array)); |
7386 | 212 array.base_addr=(int)ldt_fs->fs_seg; |
2067 | 213 array.entry_number=TEB_SEL_IDX; |
214 array.limit=array.base_addr+getpagesize()-1; | |
215 array.seg_32bit=1; | |
216 array.read_exec_only=0; | |
217 array.seg_not_present=0; | |
218 array.contents=MODIFY_LDT_CONTENTS_DATA; | |
219 array.limit_in_pages=0; | |
220 #ifdef __linux__ | |
7386 | 221 //ret=LDT_Modify(0x1, &array, sizeof(struct modify_ldt_ldt_s)); |
222 ret=modify_ldt(0x1, &array, sizeof(struct modify_ldt_ldt_s)); | |
2067 | 223 if(ret<0) |
224 { | |
225 perror("install_fs"); | |
226 printf("Couldn't install fs segment, expect segfault\n"); | |
227 } | |
228 #endif /*linux*/ | |
229 | |
230 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) | |
231 { | |
232 unsigned long d[2]; | |
233 | |
234 LDT_EntryToBytes( d, &array ); | |
10821
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
235 #if defined(__FreeBSD__) && defined(LDT_AUTO_ALLOC) |
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
236 ret = i386_set_ldt(LDT_AUTO_ALLOC, (union descriptor *)d, 1); |
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
237 array.entry_number = ret; |
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
238 fs_ldt = ret; |
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
239 #else |
2067 | 240 ret = i386_set_ldt(array.entry_number, (union descriptor *)d, 1); |
10821
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
241 #endif |
2067 | 242 if (ret < 0) |
243 { | |
244 perror("install_fs"); | |
245 printf("Couldn't install fs segment, expect segfault\n"); | |
246 printf("Did you reconfigure the kernel with \"options USER_LDT\"?\n"); | |
247 } | |
248 } | |
249 #endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */ | |
250 | |
251 #if defined(__svr4__) | |
2070
c1edbb8bfc0c
(solaris x86) C++ style variable declaration not at the start of a block does
jkeil
parents:
2069
diff
changeset
|
252 { |
2139 | 253 struct ssd ssd; |
10821
e9e5dca4af9e
FreeBSD 5.0 (libkse/libthr) support by Dan Eischen <eischen@vigrid.com>
alex
parents:
8223
diff
changeset
|
254 ssd.sel = LDT_SEL(TEB_SEL_IDX); |
2139 | 255 ssd.bo = array.base_addr; |
256 ssd.ls = array.limit - array.base_addr; | |
257 ssd.acc1 = ((array.read_exec_only == 0) << 1) | | |
258 (array.contents << 2) | | |
259 0xf0; /* P(resent) | DPL3 | S */ | |
260 ssd.acc2 = 0x4; /* byte limit, 32-bit segment */ | |
261 if (sysi86(SI86DSCR, &ssd) < 0) { | |
262 perror("sysi86(SI86DSCR)"); | |
263 printf("Couldn't install fs segment, expect segfault\n"); | |
264 } | |
2070
c1edbb8bfc0c
(solaris x86) C++ style variable declaration not at the start of a block does
jkeil
parents:
2069
diff
changeset
|
265 } |
2067 | 266 #endif |
267 | |
268 Setup_FS_Segment(); | |
269 | |
7386 | 270 ldt_fs->prev_struct = (char*)malloc(sizeof(char) * 8); |
271 *(void**)array.base_addr = ldt_fs->prev_struct; | |
272 | |
273 return ldt_fs; | |
2067 | 274 } |
275 | |
7386 | 276 void Restore_LDT_Keeper(ldt_fs_t* ldt_fs) |
2067 | 277 { |
7386 | 278 if (ldt_fs == NULL || ldt_fs->fs_seg == 0) |
2067 | 279 return; |
7386 | 280 if (ldt_fs->prev_struct) |
281 free(ldt_fs->prev_struct); | |
282 munmap((char*)ldt_fs->fs_seg, getpagesize()); | |
283 ldt_fs->fs_seg = 0; | |
284 close(ldt_fs->fd); | |
285 free(ldt_fs); | |
2067 | 286 } |