2001-10-04 00:07:15 +00:00
/**
* ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
* This file MUST be in main library because LDT must
* be modified before program creates first thread
* - avifile includes this file from C + + code
* and initializes it at the start of player !
2002-09-13 19:43:17 +00:00
* it might sound like a hack and it really is - but
* as aviplay is deconding video with more than just one
* thread currently it ' s necessary to do it this way
* this might change in the future
2001-10-04 00:07:15 +00:00
*/
2002-09-13 19:43:17 +00:00
/* applied some modification to make make our xine friend more happy */
2005-04-15 20:17:14 +00:00
/*
2006-06-22 13:34:00 +00:00
* Modified for use with MPlayer , detailed changelog at
* http : //svn.mplayerhq.hu/mplayer/trunk/
2005-04-15 20:17:14 +00:00
*/
2008-03-01 10:31:51 +00:00
# include "config.h"
2001-10-08 22:26:14 +00:00
# include "ldt_keeper.h"
2001-10-04 00:07:15 +00:00
# include <string.h>
# include <stdlib.h>
# include <errno.h>
# include <fcntl.h>
2008-03-01 10:31:51 +00:00
# ifdef HAVE_SYS_MMAN_H
2001-10-04 00:07:15 +00:00
# include <sys/mman.h>
2008-03-03 09:47:01 +00:00
# else
# include "osdep/mmap.h"
2008-03-01 10:31:51 +00:00
# endif
2001-10-04 00:07:15 +00:00
# include <sys/types.h>
# include <stdio.h>
# include <unistd.h>
2006-11-25 01:22:20 +00:00
# include "osdep/mmap_anon.h"
2006-11-27 02:44:06 +00:00
# include "mp_msg.h"
2001-10-04 00:07:15 +00:00
# ifdef __linux__
# include <asm/unistd.h>
# include <asm/ldt.h>
2002-11-16 09:38:23 +00:00
// 2.5.xx+ calls this user_desc:
# include <linux/version.h>
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,47)
# define modify_ldt_ldt_s user_desc
# endif
2004-09-16 07:58:19 +00:00
/// declare modify_ldt with the _syscall3 macro for older glibcs
2004-09-17 10:37:56 +00:00
# if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0))
2004-09-16 07:58:19 +00:00
_syscall3 ( int , modify_ldt , int , func , void * , ptr , unsigned long , bytecount ) ;
# else
2002-09-13 19:43:17 +00:00
int modify_ldt ( int func , void * ptr , unsigned long bytecount ) ;
2004-09-16 07:58:19 +00:00
# endif
2001-10-04 00:07:15 +00:00
# else
2005-05-25 08:48:32 +00:00
# if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
2002-04-27 22:42:27 +00:00
# include <machine/segments.h>
2001-10-04 00:07:15 +00:00
# include <machine/sysarch.h>
2010-02-08 10:05:49 +00:00
# elif defined(__APPLE__)
2008-02-24 12:18:01 +00:00
# include <architecture/i386/table.h>
# include <i386/user_ldt.h>
2010-02-08 10:05:49 +00:00
# elif defined(__svr4__)
2001-10-04 00:07:15 +00:00
# include <sys/segment.h>
# include <sys/sysi86.h>
2007-03-18 22:18:11 +00:00
/* solaris x86: add missing prototype for sysi86(), but only when sysi86(int, void*) is known to be valid */
# ifdef HAVE_SYSI86_iv
2002-09-13 19:43:17 +00:00
int sysi86 ( int , void * ) ;
2006-04-30 21:17:30 +00:00
# endif
2001-10-04 00:07:15 +00:00
2001-10-08 22:26:14 +00:00
# ifndef NUMSYSLDTS /* SunOS 2.5.1 does not define NUMSYSLDTS */
# define NUMSYSLDTS 6 /* Let's hope the SunOS 5.8 value is OK */
2001-10-04 00:07:15 +00:00
# endif
# define TEB_SEL_IDX NUMSYSLDTS
# endif
# define LDT_ENTRIES 8192
# define LDT_ENTRY_SIZE 8
# pragma pack(4)
struct modify_ldt_ldt_s {
unsigned int entry_number ;
unsigned long base_addr ;
unsigned int limit ;
unsigned int seg_32bit : 1 ;
unsigned int contents : 2 ;
unsigned int read_exec_only : 1 ;
unsigned int limit_in_pages : 1 ;
unsigned int seg_not_present : 1 ;
unsigned int useable : 1 ;
} ;
# define MODIFY_LDT_CONTENTS_DATA 0
# define MODIFY_LDT_CONTENTS_STACK 1
# define MODIFY_LDT_CONTENTS_CODE 2
# endif
/* user level (privilege level: 3) ldt (1<<2) segment selector */
# define LDT_SEL(idx) ((idx) << 3 | 1 << 2 | 3)
2002-09-13 19:43:17 +00:00
/* i got this value from wine sources, it's the first free LDT entry */
2006-11-27 02:44:06 +00:00
# if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(LDT_AUTO_ALLOC)
2003-09-06 00:14:08 +00:00
# define TEB_SEL_IDX LDT_AUTO_ALLOC
2006-11-27 02:44:06 +00:00
# define USE_LDT_AA
2003-09-06 00:14:08 +00:00
# endif
2001-10-04 00:07:15 +00:00
# ifndef TEB_SEL_IDX
2002-09-13 19:43:17 +00:00
# define TEB_SEL_IDX 17
2001-10-04 00:07:15 +00:00
# endif
2003-09-06 00:14:08 +00:00
static unsigned int fs_ldt = TEB_SEL_IDX ;
2001-10-04 00:07:15 +00:00
/**
* here is a small logical problem with Restore for multithreaded programs -
* in C + + we use static class for this . . .
*/
void Setup_FS_Segment ( void )
{
2003-09-06 00:14:08 +00:00
unsigned int ldt_desc = LDT_SEL ( fs_ldt ) ;
2008-10-16 20:17:56 +00:00
__asm__ volatile (
2003-09-06 00:14:08 +00:00
" movl %0,%%eax; movw %%ax, %%fs " : : " r " ( ldt_desc )
2004-12-21 23:26:45 +00:00
: " eax "
2001-10-04 00:07:15 +00:00
) ;
}
2002-09-13 19:43:17 +00:00
/* we don't need this - use modify_ldt instead */
#if 0
2001-10-04 00:07:15 +00:00
# ifdef __linux__
/* XXX: why is this routine from libc redefined here? */
/* NOTE: the redefined version ignores the count param, count is hardcoded as 16 */
static int LDT_Modify ( int func , struct modify_ldt_ldt_s * ptr ,
unsigned long count )
{
int res ;
# ifdef __PIC__
2008-10-16 20:17:56 +00:00
__asm__ volatile ( " pushl %%ebx \n \t "
2001-10-04 00:07:15 +00:00
" movl %2,%%ebx \n \t "
" int $0x80 \n \t "
" popl %%ebx "
: " =a " ( res )
: " 0 " ( __NR_modify_ldt ) ,
" r " ( func ) ,
" c " ( ptr ) ,
" d " ( 16 ) //sizeof(*ptr) from kernel point of view
: " esi " ) ;
# else
2008-10-16 20:17:56 +00:00
__asm__ volatile ( " int $0x80 "
2001-10-04 00:07:15 +00:00
: " =a " ( res )
: " 0 " ( __NR_modify_ldt ) ,
" b " ( func ) ,
" c " ( ptr ) ,
" d " ( 16 )
: " esi " ) ;
# endif /* __PIC__ */
if ( res > = 0 ) return res ;
errno = - res ;
return - 1 ;
}
# endif
2002-09-13 19:43:17 +00:00
# endif
2001-10-04 00:07:15 +00:00
2006-11-27 02:44:06 +00:00
# if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2001-10-04 00:07:15 +00:00
static void LDT_EntryToBytes ( unsigned long * buffer , const struct modify_ldt_ldt_s * content )
{
* buffer + + = ( ( content - > base_addr & 0x0000ffff ) < < 16 ) |
( content - > limit & 0x0ffff ) ;
* buffer = ( content - > base_addr & 0xff000000 ) |
( ( content - > base_addr & 0x00ff0000 ) > > 16 ) |
( content - > limit & 0xf0000 ) |
( content - > contents < < 10 ) |
( ( content - > read_exec_only = = 0 ) < < 9 ) |
( ( content - > seg_32bit ! = 0 ) < < 22 ) |
( ( content - > limit_in_pages ! = 0 ) < < 23 ) |
0xf000 ;
}
# endif
2002-11-17 17:41:19 +00:00
void * fs_seg = 0 ;
2002-09-13 19:43:17 +00:00
ldt_fs_t * Setup_LDT_Keeper ( void )
2001-10-04 00:07:15 +00:00
{
struct modify_ldt_ldt_s array ;
int ret ;
2010-02-26 15:01:37 +00:00
ldt_fs_t * ldt_fs = malloc ( sizeof ( ldt_fs_t ) ) ;
2001-10-04 00:07:15 +00:00
2002-09-13 19:43:17 +00:00
if ( ! ldt_fs )
return NULL ;
2001-10-04 00:07:15 +00:00
2006-11-27 02:44:06 +00:00
# ifdef __APPLE__
if ( getenv ( " DYLD_BIND_AT_LAUNCH " ) = = NULL )
2010-03-07 16:33:01 +00:00
mp_tmsg ( MSGT_LOADER , MSGL_WARN , " WARNING: Attempting to use DLL codecs but environment variable \n DYLD_BIND_AT_LAUNCH not set. This will likely crash. \n " ) ;
2006-11-27 02:44:06 +00:00
# endif /* __APPLE__ */
2009-07-06 23:26:13 +00:00
2002-11-17 17:41:19 +00:00
fs_seg =
2006-11-26 13:09:46 +00:00
ldt_fs - > fs_seg = mmap_anon ( NULL , getpagesize ( ) , PROT_READ | PROT_WRITE , MAP_PRIVATE , 0 ) ;
2002-09-13 19:43:17 +00:00
if ( ldt_fs - > fs_seg = = ( void * ) - 1 )
2001-10-04 00:07:15 +00:00
{
perror ( " ERROR: Couldn't allocate memory for fs segment " ) ;
2002-09-13 19:43:17 +00:00
free ( ldt_fs ) ;
return NULL ;
2001-10-04 00:07:15 +00:00
}
2002-09-13 19:43:17 +00:00
* ( void * * ) ( ( char * ) ldt_fs - > fs_seg + 0x18 ) = ldt_fs - > fs_seg ;
2005-01-19 17:03:59 +00:00
memset ( & array , 0 , sizeof ( array ) ) ;
2002-09-13 19:43:17 +00:00
array . base_addr = ( int ) ldt_fs - > fs_seg ;
2001-10-04 00:07:15 +00:00
array . entry_number = TEB_SEL_IDX ;
array . limit = array . base_addr + getpagesize ( ) - 1 ;
array . seg_32bit = 1 ;
array . read_exec_only = 0 ;
array . seg_not_present = 0 ;
array . contents = MODIFY_LDT_CONTENTS_DATA ;
array . limit_in_pages = 0 ;
# ifdef __linux__
2002-09-13 19:43:17 +00:00
//ret=LDT_Modify(0x1, &array, sizeof(struct modify_ldt_ldt_s));
ret = modify_ldt ( 0x1 , & array , sizeof ( struct modify_ldt_ldt_s ) ) ;
2001-10-04 00:07:15 +00:00
if ( ret < 0 )
{
perror ( " install_fs " ) ;
printf ( " Couldn't install fs segment, expect segfault \n " ) ;
}
2010-02-08 10:05:49 +00:00
# elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2001-10-04 00:07:15 +00:00
{
unsigned long d [ 2 ] ;
LDT_EntryToBytes ( d , & array ) ;
2006-11-27 02:44:06 +00:00
# ifdef USE_LDT_AA
2003-09-06 00:14:08 +00:00
ret = i386_set_ldt ( LDT_AUTO_ALLOC , ( union descriptor * ) d , 1 ) ;
array . entry_number = ret ;
fs_ldt = ret ;
# else
2001-10-04 00:07:15 +00:00
ret = i386_set_ldt ( array . entry_number , ( union descriptor * ) d , 1 ) ;
2003-09-06 00:14:08 +00:00
# endif
2001-10-04 00:07:15 +00:00
if ( ret < 0 )
{
perror ( " install_fs " ) ;
printf ( " Couldn't install fs segment, expect segfault \n " ) ;
printf ( " Did you reconfigure the kernel with \" options USER_LDT \" ? \n " ) ;
2006-02-12 14:14:12 +00:00
# ifdef __OpenBSD__
printf ( " On newer OpenBSD systems did you set machdep.userldt to 1? \n " ) ;
# endif
2001-10-04 00:07:15 +00:00
}
}
2010-02-08 10:05:49 +00:00
# elif defined(__svr4__)
2001-10-04 11:17:39 +00:00
{
2001-10-08 22:26:14 +00:00
struct ssd ssd ;
2003-09-06 00:14:08 +00:00
ssd . sel = LDT_SEL ( TEB_SEL_IDX ) ;
2001-10-08 22:26:14 +00:00
ssd . bo = array . base_addr ;
ssd . ls = array . limit - array . base_addr ;
ssd . acc1 = ( ( array . read_exec_only = = 0 ) < < 1 ) |
( array . contents < < 2 ) |
0xf0 ; /* P(resent) | DPL3 | S */
ssd . acc2 = 0x4 ; /* byte limit, 32-bit segment */
if ( sysi86 ( SI86DSCR , & ssd ) < 0 ) {
perror ( " sysi86(SI86DSCR) " ) ;
printf ( " Couldn't install fs segment, expect segfault \n " ) ;
}
2001-10-04 11:17:39 +00:00
}
2010-02-12 01:38:14 +00:00
# elif defined(__OS2__)
/* convert flat addr to sel idx for LDT_SEL() */
fs_ldt = ( uintptr_t ) fs_seg > > 16 ;
2001-10-04 00:07:15 +00:00
# endif
Setup_FS_Segment ( ) ;
2006-07-02 03:59:36 +00:00
ldt_fs - > prev_struct = malloc ( 8 ) ;
2002-09-13 19:43:17 +00:00
* ( void * * ) array . base_addr = ldt_fs - > prev_struct ;
return ldt_fs ;
2001-10-04 00:07:15 +00:00
}
2002-09-13 19:43:17 +00:00
void Restore_LDT_Keeper ( ldt_fs_t * ldt_fs )
2001-10-04 00:07:15 +00:00
{
2002-09-13 19:43:17 +00:00
if ( ldt_fs = = NULL | | ldt_fs - > fs_seg = = 0 )
2001-10-04 00:07:15 +00:00
return ;
2002-09-13 19:43:17 +00:00
if ( ldt_fs - > prev_struct )
free ( ldt_fs - > prev_struct ) ;
munmap ( ( char * ) ldt_fs - > fs_seg , getpagesize ( ) ) ;
ldt_fs - > fs_seg = 0 ;
free ( ldt_fs ) ;
2001-10-04 00:07:15 +00:00
}