Moved LDT selector allocation routines to libwine.
Added support for correct locking of all LDT operations. Added separate functions to manipulate the %fs selector, which allows using a global GDT selector on recent Linux kernels.
This commit is contained in:
parent
28d65b1ac9
commit
ce13153821
|
@ -49,6 +49,21 @@ extern int __wine_set_signal_handler(unsigned, int (*)(unsigned));
|
|||
|
||||
extern int main_create_flags;
|
||||
|
||||
static CRITICAL_SECTION ldt_section = CRITICAL_SECTION_INIT("ldt_section");
|
||||
|
||||
/***********************************************************************
|
||||
* locking for LDT routines
|
||||
*/
|
||||
static void ldt_lock(void)
|
||||
{
|
||||
EnterCriticalSection( &ldt_section );
|
||||
}
|
||||
|
||||
static void ldt_unlock(void)
|
||||
{
|
||||
LeaveCriticalSection( &ldt_section );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* KERNEL process initialisation routine
|
||||
*/
|
||||
|
@ -114,6 +129,9 @@ static BOOL process_attach(void)
|
|||
/* Create the shared heap for broken win95 native dlls */
|
||||
HeapCreate( HEAP_SHARED, 0, 0 );
|
||||
|
||||
/* initialize LDT locking */
|
||||
wine_ldt_init_locking( ldt_lock, ldt_unlock );
|
||||
|
||||
/* finish the process initialisation for console bits, if needed */
|
||||
__wine_set_signal_handler(SIGINT, CONSOLE_HandleCtrlC);
|
||||
|
||||
|
|
|
@ -876,15 +876,17 @@ void WINAPI DOSVM_Int31Handler( CONTEXT86 *context )
|
|||
case 0x0006: /* Get selector base address */
|
||||
TRACE( "get selector base address (0x%04x)\n", BX_reg(context) );
|
||||
{
|
||||
LDT_ENTRY entry;
|
||||
WORD sel = BX_reg(context);
|
||||
if (IS_SELECTOR_SYSTEM(sel) || IS_SELECTOR_FREE(sel))
|
||||
wine_ldt_get_entry( sel, &entry );
|
||||
if (wine_ldt_is_empty(&entry))
|
||||
{
|
||||
context->Eax = 0x8022; /* invalid selector */
|
||||
SET_CFLAG(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD base = GetSelectorBase( sel );
|
||||
void *base = wine_ldt_get_base(&entry);
|
||||
SET_CX( context, HIWORD(base) );
|
||||
SET_DX( context, LOWORD(base) );
|
||||
}
|
||||
|
|
|
@ -145,11 +145,7 @@ extern char IO_pp_init(void);
|
|||
* selector which is neither system selector nor zero.
|
||||
*/
|
||||
#define CTX_SEG_OFF_TO_LIN(context,seg,off) \
|
||||
(ISV86(context) ? PTR_REAL_TO_LIN((seg),(off)) : \
|
||||
(!seg || IS_SELECTOR_SYSTEM(seg))? (void *)(ULONG_PTR)(off) : \
|
||||
(IS_SELECTOR_32BIT(seg) ? \
|
||||
(void *)((off) + (char*)MapSL(MAKESEGPTR((seg),0))) : \
|
||||
MapSL(MAKESEGPTR((seg),(off)))))
|
||||
(ISV86(context) ? PTR_REAL_TO_LIN((seg),(off)) : wine_ldt_get_ptr((seg),(off)))
|
||||
|
||||
#define INT_BARF(context,num) \
|
||||
ERR( "int%x: unknown/not implemented parameters:\n" \
|
||||
|
|
|
@ -28,13 +28,9 @@ extern WORD SELECTOR_AllocBlock( const void *base, DWORD size, unsigned char fla
|
|||
extern WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size );
|
||||
extern void SELECTOR_FreeBlock( WORD sel );
|
||||
|
||||
#define FIRST_LDT_ENTRY_TO_ALLOC 17
|
||||
|
||||
#define IS_SELECTOR_FREE(sel) (!(wine_ldt_copy.flags[LOWORD(sel) >> 3] & WINE_LDT_FLAGS_ALLOCATED))
|
||||
|
||||
/* Determine if sel is a system selector (i.e. not managed by Wine) */
|
||||
#define IS_SELECTOR_SYSTEM(sel) \
|
||||
(!((sel) & 4) || ((LOWORD(sel) >> 3) < FIRST_LDT_ENTRY_TO_ALLOC))
|
||||
(!((sel) & 4) || ((LOWORD(sel) >> 3) < WINE_LDT_FIRST_ENTRY))
|
||||
#define IS_SELECTOR_32BIT(sel) \
|
||||
(IS_SELECTOR_SYSTEM(sel) || (wine_ldt_copy.flags[LOWORD(sel) >> 3] & WINE_LDT_FLAGS_32BIT))
|
||||
|
||||
|
|
|
@ -68,8 +68,23 @@ extern int* (*wine_h_errno_location)(void);
|
|||
|
||||
/* LDT management */
|
||||
|
||||
extern void wine_ldt_init_locking( void (*lock_func)(void), void (*unlock_func)(void) );
|
||||
extern void wine_ldt_get_entry( unsigned short sel, LDT_ENTRY *entry );
|
||||
extern int wine_ldt_set_entry( unsigned short sel, const LDT_ENTRY *entry );
|
||||
extern void *wine_ldt_get_ptr( unsigned short sel, unsigned int offset );
|
||||
extern unsigned short wine_ldt_alloc_entries( int count );
|
||||
extern unsigned short wine_ldt_realloc_entries( unsigned short sel, int oldcount, int newcount );
|
||||
extern void wine_ldt_free_entries( unsigned short sel, int count );
|
||||
#ifdef __i386__
|
||||
extern unsigned short wine_ldt_alloc_fs(void);
|
||||
extern void wine_ldt_init_fs( unsigned short sel, const LDT_ENTRY *entry );
|
||||
extern void wine_ldt_free_fs( unsigned short sel );
|
||||
#else /* __i386__ */
|
||||
static inline unsigned short wine_ldt_alloc_fs(void) { return 0x0b; /* pseudo GDT selector */ }
|
||||
static inline void wine_ldt_init_fs( unsigned short sel, const LDT_ENTRY *entry ) { }
|
||||
static inline void wine_ldt_free_fs( unsigned short sel ) { }
|
||||
#endif /* __i386__ */
|
||||
|
||||
|
||||
/* the local copy of the LDT */
|
||||
#ifdef __CYGWIN__
|
||||
|
@ -96,6 +111,8 @@ WINE_LDT_EXTERN struct __wine_ldt_copy
|
|||
#define WINE_LDT_FLAGS_32BIT 0x40 /* Segment is 32-bit (code or stack) */
|
||||
#define WINE_LDT_FLAGS_ALLOCATED 0x80 /* Segment is allocated (no longer free) */
|
||||
|
||||
#define WINE_LDT_FIRST_ENTRY 17
|
||||
|
||||
/* helper functions to manipulate the LDT_ENTRY structure */
|
||||
inline static void wine_ldt_set_base( LDT_ENTRY *ent, const void *base )
|
||||
{
|
||||
|
@ -136,6 +153,11 @@ inline static unsigned char wine_ldt_get_flags( const LDT_ENTRY *ent )
|
|||
if (ent->HighWord.Bits.Default_Big) ret |= WINE_LDT_FLAGS_32BIT;
|
||||
return ret;
|
||||
}
|
||||
inline static int wine_ldt_is_empty( const LDT_ENTRY *ent )
|
||||
{
|
||||
const DWORD *dw = (const DWORD *)ent;
|
||||
return (dw[0] | dw[1]) == 0;
|
||||
}
|
||||
|
||||
/* segment register access */
|
||||
|
||||
|
|
325
library/ldt.c
325
library/ldt.c
|
@ -22,6 +22,7 @@
|
|||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -52,11 +53,25 @@ struct modify_ldt_s
|
|||
unsigned int useable:1;
|
||||
};
|
||||
|
||||
static inline int modify_ldt( int func, struct modify_ldt_s *ptr,
|
||||
unsigned long count )
|
||||
#ifndef SYS_set_thread_area
|
||||
#define SYS_set_thread_area 243
|
||||
#endif
|
||||
|
||||
static inline void fill_modify_ldt_struct( struct modify_ldt_s *ptr, const LDT_ENTRY *entry )
|
||||
{
|
||||
ptr->base_addr = (unsigned long)wine_ldt_get_base(entry);
|
||||
ptr->limit = entry->LimitLow | (entry->HighWord.Bits.LimitHi << 16);
|
||||
ptr->seg_32bit = entry->HighWord.Bits.Default_Big;
|
||||
ptr->contents = (entry->HighWord.Bits.Type >> 2) & 3;
|
||||
ptr->read_exec_only = !(entry->HighWord.Bits.Type & 2);
|
||||
ptr->limit_in_pages = entry->HighWord.Bits.Granularity;
|
||||
ptr->seg_not_present = !entry->HighWord.Bits.Pres;
|
||||
ptr->useable = entry->HighWord.Bits.Sys;
|
||||
}
|
||||
|
||||
static inline int modify_ldt( int func, struct modify_ldt_s *ptr, unsigned long count )
|
||||
{
|
||||
int res;
|
||||
#ifdef __PIC__
|
||||
__asm__ __volatile__( "pushl %%ebx\n\t"
|
||||
"movl %2,%%ebx\n\t"
|
||||
"int $0x80\n\t"
|
||||
|
@ -66,14 +81,20 @@ static inline int modify_ldt( int func, struct modify_ldt_s *ptr,
|
|||
"r" (func),
|
||||
"c" (ptr),
|
||||
"d" (count) );
|
||||
#else
|
||||
__asm__ __volatile__("int $0x80"
|
||||
: "=a" (res)
|
||||
: "0" (SYS_modify_ldt),
|
||||
"b" (func),
|
||||
"c" (ptr),
|
||||
"d" (count) );
|
||||
#endif /* __PIC__ */
|
||||
if (res >= 0) return res;
|
||||
errno = -res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int set_thread_area( struct modify_ldt_s *ptr )
|
||||
{
|
||||
int res;
|
||||
__asm__ __volatile__( "pushl %%ebx\n\t"
|
||||
"movl %2,%%ebx\n\t"
|
||||
"int $0x80\n\t"
|
||||
"popl %%ebx"
|
||||
: "=a" (res)
|
||||
: "0" (SYS_set_thread_area), "r" (ptr) );
|
||||
if (res >= 0) return res;
|
||||
errno = -res;
|
||||
return -1;
|
||||
|
@ -101,32 +122,67 @@ extern int i386_set_ldt(int, union descriptor *, int);
|
|||
/* local copy of the LDT */
|
||||
struct __wine_ldt_copy wine_ldt_copy;
|
||||
|
||||
static const LDT_ENTRY null_entry; /* all-zeros, used to clear LDT entries */
|
||||
|
||||
#define LDT_SIZE 8192
|
||||
|
||||
/* empty function for default locks */
|
||||
static void nop(void) { }
|
||||
|
||||
static void (*lock_ldt)(void) = nop;
|
||||
static void (*unlock_ldt)(void) = nop;
|
||||
|
||||
|
||||
static inline int is_gdt_sel( unsigned short sel ) { return !(sel & 4); }
|
||||
|
||||
/***********************************************************************
|
||||
* ldt_get_entry
|
||||
* wine_ldt_init_locking
|
||||
*
|
||||
* Retrieve an LDT entry.
|
||||
* Set the LDT locking/unlocking functions.
|
||||
*/
|
||||
void wine_ldt_get_entry( unsigned short sel, LDT_ENTRY *entry )
|
||||
void wine_ldt_init_locking( void (*lock_func)(void), void (*unlock_func)(void) )
|
||||
{
|
||||
int index = sel >> 3;
|
||||
wine_ldt_set_base( entry, wine_ldt_copy.base[index] );
|
||||
wine_ldt_set_limit( entry, wine_ldt_copy.limit[index] );
|
||||
wine_ldt_set_flags( entry, wine_ldt_copy.flags[index] );
|
||||
lock_ldt = lock_func;
|
||||
unlock_ldt = unlock_func;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* ldt_set_entry
|
||||
* wine_ldt_get_entry
|
||||
*
|
||||
* Set an LDT entry.
|
||||
* Retrieve an LDT entry. Return a null entry if selector is not allocated.
|
||||
*/
|
||||
int wine_ldt_set_entry( unsigned short sel, const LDT_ENTRY *entry )
|
||||
void wine_ldt_get_entry( unsigned short sel, LDT_ENTRY *entry )
|
||||
{
|
||||
int index = sel >> 3;
|
||||
|
||||
if (is_gdt_sel(sel))
|
||||
{
|
||||
*entry = null_entry;
|
||||
return;
|
||||
}
|
||||
lock_ldt();
|
||||
if (wine_ldt_copy.flags[index] & WINE_LDT_FLAGS_ALLOCATED)
|
||||
{
|
||||
wine_ldt_set_base( entry, wine_ldt_copy.base[index] );
|
||||
wine_ldt_set_limit( entry, wine_ldt_copy.limit[index] );
|
||||
wine_ldt_set_flags( entry, wine_ldt_copy.flags[index] );
|
||||
}
|
||||
else *entry = null_entry;
|
||||
unlock_ldt();
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* internal_set_entry
|
||||
*
|
||||
* Set an LDT entry, without locking. For internal use only.
|
||||
*/
|
||||
static int internal_set_entry( unsigned short sel, const LDT_ENTRY *entry )
|
||||
{
|
||||
int ret = 0, index = sel >> 3;
|
||||
|
||||
/* Entry 0 must not be modified; its base and limit are always 0 */
|
||||
if (!index) return 0;
|
||||
if (index < WINE_LDT_FIRST_ENTRY) return 0; /* cannot modify reserved entries */
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
|
@ -134,16 +190,8 @@ int wine_ldt_set_entry( unsigned short sel, const LDT_ENTRY *entry )
|
|||
{
|
||||
struct modify_ldt_s ldt_info;
|
||||
|
||||
ldt_info.entry_number = index;
|
||||
ldt_info.base_addr = (unsigned long)wine_ldt_get_base(entry);
|
||||
ldt_info.limit = entry->LimitLow | (entry->HighWord.Bits.LimitHi << 16);
|
||||
ldt_info.seg_32bit = entry->HighWord.Bits.Default_Big;
|
||||
ldt_info.contents = (entry->HighWord.Bits.Type >> 2) & 3;
|
||||
ldt_info.read_exec_only = !(entry->HighWord.Bits.Type & 2);
|
||||
ldt_info.limit_in_pages = entry->HighWord.Bits.Granularity;
|
||||
ldt_info.seg_not_present = !entry->HighWord.Bits.Pres;
|
||||
ldt_info.useable = entry->HighWord.Bits.Sys;
|
||||
|
||||
ldt_info.entry_number = index;
|
||||
fill_modify_ldt_struct( &ldt_info, entry );
|
||||
if ((ret = modify_ldt(0x11, &ldt_info, sizeof(ldt_info))) < 0)
|
||||
perror( "modify_ldt" );
|
||||
}
|
||||
|
@ -192,10 +240,216 @@ int wine_ldt_set_entry( unsigned short sel, const LDT_ENTRY *entry )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wine_ldt_set_entry
|
||||
*
|
||||
* Set an LDT entry.
|
||||
*/
|
||||
int wine_ldt_set_entry( unsigned short sel, const LDT_ENTRY *entry )
|
||||
{
|
||||
int ret;
|
||||
|
||||
lock_ldt();
|
||||
ret = internal_set_entry( sel, entry );
|
||||
unlock_ldt();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wine_ldt_get_ptr
|
||||
*
|
||||
* Convert a segment:offset pair to a linear pointer.
|
||||
* Note: we don't lock the LDT since this has to be fast.
|
||||
*/
|
||||
void *wine_ldt_get_ptr( unsigned short sel, unsigned int offset )
|
||||
{
|
||||
int index;
|
||||
|
||||
if (is_gdt_sel(sel)) /* GDT selector */
|
||||
return (void *)offset;
|
||||
if ((index = (sel >> 3)) < WINE_LDT_FIRST_ENTRY) /* system selector */
|
||||
return (void *)offset;
|
||||
if (!(wine_ldt_copy.flags[index] & WINE_LDT_FLAGS_32BIT)) offset &= 0xffff;
|
||||
return (char *)wine_ldt_copy.base[index] + offset;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wine_ldt_alloc_entries
|
||||
*
|
||||
* Allocate a number of consecutive ldt entries, without setting the LDT contents.
|
||||
* Return a selector for the first entry.
|
||||
*/
|
||||
unsigned short wine_ldt_alloc_entries( int count )
|
||||
{
|
||||
int i, index, size = 0;
|
||||
|
||||
if (count <= 0) return 0;
|
||||
lock_ldt();
|
||||
for (i = WINE_LDT_FIRST_ENTRY; i < LDT_SIZE; i++)
|
||||
{
|
||||
if (wine_ldt_copy.flags[i] & WINE_LDT_FLAGS_ALLOCATED) size = 0;
|
||||
else if (++size >= count) /* found a large enough block */
|
||||
{
|
||||
index = i - size + 1;
|
||||
|
||||
/* mark selectors as allocated */
|
||||
for (i = 0; i < count; i++) wine_ldt_copy.flags[index + i] |= WINE_LDT_FLAGS_ALLOCATED;
|
||||
unlock_ldt();
|
||||
return (index << 3) | 7;
|
||||
}
|
||||
}
|
||||
unlock_ldt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wine_ldt_realloc_entries
|
||||
*
|
||||
* Reallocate a number of consecutive ldt entries, without changing the LDT contents.
|
||||
* Return a selector for the first entry.
|
||||
*/
|
||||
unsigned short wine_ldt_realloc_entries( unsigned short sel, int oldcount, int newcount )
|
||||
{
|
||||
int i;
|
||||
|
||||
if (oldcount < newcount) /* we need to add selectors */
|
||||
{
|
||||
int index = sel >> 3;
|
||||
|
||||
lock_ldt();
|
||||
/* check if the next selectors are free */
|
||||
if (index + newcount > LDT_SIZE) i = oldcount;
|
||||
else
|
||||
for (i = oldcount; i < newcount; i++)
|
||||
if (wine_ldt_copy.flags[index+i] & WINE_LDT_FLAGS_ALLOCATED) break;
|
||||
|
||||
if (i < newcount) /* they are not free */
|
||||
{
|
||||
wine_ldt_free_entries( sel, oldcount );
|
||||
sel = wine_ldt_alloc_entries( newcount );
|
||||
}
|
||||
else /* mark the selectors as allocated */
|
||||
{
|
||||
for (i = oldcount; i < newcount; i++)
|
||||
wine_ldt_copy.flags[index+i] |= WINE_LDT_FLAGS_ALLOCATED;
|
||||
}
|
||||
unlock_ldt();
|
||||
}
|
||||
else if (oldcount > newcount) /* we need to remove selectors */
|
||||
{
|
||||
wine_ldt_free_entries( sel + (newcount << 3), newcount - oldcount );
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wine_ldt_free_entries
|
||||
*
|
||||
* Free a number of consecutive ldt entries and clear their contents.
|
||||
*/
|
||||
void wine_ldt_free_entries( unsigned short sel, int count )
|
||||
{
|
||||
int index;
|
||||
|
||||
lock_ldt();
|
||||
for (index = sel >> 3; count > 0; count--, index++)
|
||||
{
|
||||
internal_set_entry( sel, &null_entry );
|
||||
wine_ldt_copy.flags[index] = 0;
|
||||
}
|
||||
unlock_ldt();
|
||||
}
|
||||
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
static int fs_gdt_index = -1; /* GDT index for %fs, or 0 if GDT not supported on this kernel */
|
||||
|
||||
/***********************************************************************
|
||||
* wine_ldt_alloc_fs
|
||||
*
|
||||
* Allocate an LDT entry for a %fs selector, reusing a global
|
||||
* GDT selector if possible. Return the selector value.
|
||||
*/
|
||||
unsigned short wine_ldt_alloc_fs(void)
|
||||
{
|
||||
if (fs_gdt_index == -1)
|
||||
{
|
||||
#ifdef __linux__
|
||||
struct modify_ldt_s ldt_info;
|
||||
int ret;
|
||||
|
||||
ldt_info.entry_number = -1;
|
||||
fill_modify_ldt_struct( &ldt_info, &null_entry );
|
||||
if ((ret = set_thread_area( &ldt_info ) < 0))
|
||||
{
|
||||
fs_gdt_index = 0; /* don't try it again */
|
||||
if (errno != ENOSYS) perror( "set_thread_area" );
|
||||
}
|
||||
else fs_gdt_index = ldt_info.entry_number;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
if (fs_gdt_index > 0) return (fs_gdt_index << 3) | 3;
|
||||
return wine_ldt_alloc_entries( 1 );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wine_ldt_init_fs
|
||||
*
|
||||
* Initialize the entry for the %fs selector of the current thread, and
|
||||
* set the thread %fs register.
|
||||
*
|
||||
* Note: this runs in the context of the new thread, so cannot acquire locks.
|
||||
*/
|
||||
void wine_ldt_init_fs( unsigned short sel, const LDT_ENTRY *entry )
|
||||
{
|
||||
if (is_gdt_sel(sel))
|
||||
{
|
||||
#ifdef __linux__
|
||||
struct modify_ldt_s ldt_info;
|
||||
int ret;
|
||||
|
||||
ldt_info.entry_number = sel >> 3;
|
||||
assert( ldt_info.entry_number == fs_gdt_index );
|
||||
fill_modify_ldt_struct( &ldt_info, entry );
|
||||
if ((ret = set_thread_area( &ldt_info ) < 0)) perror( "set_thread_area" );
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
else /* LDT selector */
|
||||
{
|
||||
internal_set_entry( sel, entry );
|
||||
}
|
||||
wine_set_fs( sel );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wine_ldt_free_fs
|
||||
*
|
||||
* Free a %fs selector returned by wine_ldt_alloc_fs.
|
||||
*/
|
||||
void wine_ldt_free_fs( unsigned short sel )
|
||||
{
|
||||
if (is_gdt_sel(sel)) return; /* nothing to do */
|
||||
if (!((wine_get_fs() ^ sel) & ~3))
|
||||
{
|
||||
/* FIXME: if freeing current %fs we cannot acquire locks */
|
||||
wine_set_fs( 0 );
|
||||
internal_set_entry( sel, &null_entry );
|
||||
wine_ldt_copy.flags[sel >> 3] = 0;
|
||||
}
|
||||
else wine_ldt_free_entries( sel, 1 );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* selector access functions
|
||||
*/
|
||||
#ifdef __i386__
|
||||
# ifndef _MSC_VER
|
||||
/* Nothing needs to be done for MS C, it will do with inline versions from the winnt.h */
|
||||
__ASM_GLOBAL_FUNC( wine_get_cs, "movw %cs,%ax\n\tret" )
|
||||
|
@ -207,4 +461,5 @@ __ASM_GLOBAL_FUNC( wine_get_ss, "movw %ss,%ax\n\tret" )
|
|||
__ASM_GLOBAL_FUNC( wine_set_fs, "movl 4(%esp),%eax\n\tmovw %ax,%fs\n\tret" )
|
||||
__ASM_GLOBAL_FUNC( wine_set_gs, "movl 4(%esp),%eax\n\tmovw %ax,%gs\n\tret" )
|
||||
# endif /* defined(_MSC_VER) */
|
||||
#endif /* defined(__i386__) */
|
||||
|
||||
#endif /* __i386__ */
|
||||
|
|
|
@ -790,17 +790,6 @@ FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance )
|
|||
return (FARPROC16)0;
|
||||
}
|
||||
|
||||
if (hInstance)
|
||||
{
|
||||
if ( (!(hInstance & 4)) ||
|
||||
((hInstance != 0xffff) && IS_SELECTOR_FREE(hInstance|7)) )
|
||||
{
|
||||
WARN("Invalid hInstance (%04x) passed to MakeProcInstance !\n",
|
||||
hInstance);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (GlobalHandleToSel16(CURRENT_DS) != hInstanceSelector)
|
||||
&& (hInstance != 0)
|
||||
&& (hInstance != 0xffff) )
|
||||
|
|
|
@ -55,13 +55,8 @@ inline static void *make_ptr( CONTEXT86 *context, DWORD seg, DWORD off, int long
|
|||
|
||||
inline static void *get_stack( CONTEXT86 *context )
|
||||
{
|
||||
if (ISV86(context))
|
||||
return PTR_REAL_TO_LIN( context->SegSs, context->Esp );
|
||||
if (IS_SELECTOR_SYSTEM(context->SegSs))
|
||||
return (void *)context->Esp;
|
||||
if (IS_SELECTOR_32BIT(context->SegSs))
|
||||
return (char *) MapSL( MAKESEGPTR( context->SegSs, 0 ) ) + context->Esp;
|
||||
return MapSL( MAKESEGPTR( context->SegSs, LOWORD(context->Esp) ) );
|
||||
if (ISV86(context)) return PTR_REAL_TO_LIN( context->SegSs, context->Esp );
|
||||
return wine_ldt_get_ptr( context->SegSs, context->Esp );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -97,8 +92,6 @@ static BOOL INSTR_ReplaceSelector( CONTEXT86 *context, WORD *sel )
|
|||
*sel = DOSMEM_BiosDataSeg;
|
||||
return TRUE;
|
||||
}
|
||||
if (!IS_SELECTOR_SYSTEM(*sel) && !IS_SELECTOR_FREE(*sel))
|
||||
ERR("Got protection fault on valid selector, maybe your kernel is too old?\n" );
|
||||
return FALSE; /* Can't replace selector, crashdump */
|
||||
}
|
||||
|
||||
|
@ -112,6 +105,7 @@ static BYTE *INSTR_GetOperandAddr( CONTEXT86 *context, BYTE *instr,
|
|||
int long_addr, int segprefix, int *len )
|
||||
{
|
||||
int mod, rm, base, index = 0, ss = 0, seg = 0, off;
|
||||
LDT_ENTRY entry;
|
||||
|
||||
#define GET_VAL(val,type) \
|
||||
{ *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
|
||||
|
@ -253,9 +247,11 @@ static BYTE *INSTR_GetOperandAddr( CONTEXT86 *context, BYTE *instr,
|
|||
|
||||
/* Make sure the segment and offset are valid */
|
||||
if (IS_SELECTOR_SYSTEM(seg)) return (BYTE *)(base + (index << ss));
|
||||
if (((seg & 7) != 7) || IS_SELECTOR_FREE(seg)) return NULL;
|
||||
if (wine_ldt_copy.limit[seg >> 3] < (base + (index << ss))) return NULL;
|
||||
return (char *) MapSL( MAKESEGPTR( seg, 0 ) ) + base + (index << ss);
|
||||
if ((seg & 7) != 7) return NULL;
|
||||
wine_ldt_get_entry( seg, &entry );
|
||||
if (wine_ldt_is_empty( &entry )) return NULL;
|
||||
if (wine_ldt_get_limit(&entry) < (base + (index << ss))) return NULL;
|
||||
return (char *)wine_ldt_get_base(&entry) + base + (index << ss);
|
||||
#undef GET_VAL
|
||||
}
|
||||
|
||||
|
|
|
@ -42,39 +42,13 @@ inline static WORD get_sel_count( WORD sel )
|
|||
return (wine_ldt_copy.limit[sel >> __AHSHIFT] >> 16) + 1;
|
||||
}
|
||||
|
||||
static const LDT_ENTRY null_entry; /* all-zeros, used to clear LDT entries */
|
||||
|
||||
/***********************************************************************
|
||||
* SELECTOR_AllocArray
|
||||
*
|
||||
* Allocate a selector array without setting the LDT entries
|
||||
*/
|
||||
static WORD SELECTOR_AllocArray( WORD count )
|
||||
{
|
||||
WORD i, sel, size = 0;
|
||||
|
||||
if (!count) return 0;
|
||||
for (i = FIRST_LDT_ENTRY_TO_ALLOC; i < LDT_SIZE; i++)
|
||||
{
|
||||
if (wine_ldt_copy.flags[i] & WINE_LDT_FLAGS_ALLOCATED) size = 0;
|
||||
else if (++size >= count) break;
|
||||
}
|
||||
if (i == LDT_SIZE) return 0;
|
||||
sel = i - size + 1;
|
||||
|
||||
/* mark selectors as allocated */
|
||||
for (i = 0; i < count; i++) wine_ldt_copy.flags[sel + i] |= WINE_LDT_FLAGS_ALLOCATED;
|
||||
|
||||
return (sel << __AHSHIFT) | 7;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* AllocSelectorArray (KERNEL.206)
|
||||
*/
|
||||
WORD WINAPI AllocSelectorArray16( WORD count )
|
||||
{
|
||||
WORD i, sel = SELECTOR_AllocArray( count );
|
||||
WORD i, sel = wine_ldt_alloc_entries( count );
|
||||
|
||||
if (sel)
|
||||
{
|
||||
|
@ -96,7 +70,7 @@ WORD WINAPI AllocSelector16( WORD sel )
|
|||
WORD newsel, count, i;
|
||||
|
||||
count = sel ? get_sel_count(sel) : 1;
|
||||
newsel = SELECTOR_AllocArray( count );
|
||||
newsel = wine_ldt_alloc_entries( count );
|
||||
TRACE("(%04x): returning %04x\n", sel, newsel );
|
||||
if (!newsel) return 0;
|
||||
if (!sel) return newsel; /* nothing to copy */
|
||||
|
@ -115,41 +89,20 @@ WORD WINAPI AllocSelector16( WORD sel )
|
|||
*/
|
||||
WORD WINAPI FreeSelector16( WORD sel )
|
||||
{
|
||||
if (IS_SELECTOR_FREE(sel)) return sel; /* error */
|
||||
LDT_ENTRY entry;
|
||||
|
||||
wine_ldt_get_entry( sel, &entry );
|
||||
if (wine_ldt_is_empty( &entry )) return sel; /* error */
|
||||
#ifdef __i386__
|
||||
/* Check if we are freeing current %fs or %gs selector */
|
||||
/* Check if we are freeing current %fs selector */
|
||||
if (!((wine_get_fs() ^ sel) & ~3))
|
||||
{
|
||||
WARN("Freeing %%fs selector (%04x), not good.\n", wine_get_fs() );
|
||||
wine_set_fs( 0 );
|
||||
}
|
||||
if (!((wine_get_gs() ^ sel) & ~3)) wine_set_gs( 0 );
|
||||
#endif /* __i386__ */
|
||||
|
||||
wine_ldt_set_entry( sel, &null_entry );
|
||||
wine_ldt_copy.flags[sel >> __AHSHIFT] &= ~WINE_LDT_FLAGS_ALLOCATED;
|
||||
wine_ldt_free_entries( sel, 1 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* SELECTOR_FreeFs
|
||||
*
|
||||
* Free the current %fs selector.
|
||||
*/
|
||||
void SELECTOR_FreeFs(void)
|
||||
{
|
||||
WORD fs = wine_get_fs();
|
||||
if (fs)
|
||||
{
|
||||
wine_ldt_copy.flags[fs >> __AHSHIFT] &= ~WINE_LDT_FLAGS_ALLOCATED;
|
||||
wine_set_fs(0);
|
||||
wine_ldt_set_entry( fs, &null_entry );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* SELECTOR_SetEntries
|
||||
*
|
||||
|
@ -185,7 +138,7 @@ WORD SELECTOR_AllocBlock( const void *base, DWORD size, unsigned char flags )
|
|||
|
||||
if (!size) return 0;
|
||||
count = (size + 0xffff) / 0x10000;
|
||||
sel = SELECTOR_AllocArray( count );
|
||||
sel = wine_ldt_alloc_entries( count );
|
||||
if (sel) SELECTOR_SetEntries( sel, base, size, flags );
|
||||
return sel;
|
||||
}
|
||||
|
@ -213,37 +166,14 @@ void SELECTOR_FreeBlock( WORD sel )
|
|||
WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size )
|
||||
{
|
||||
LDT_ENTRY entry;
|
||||
WORD i, oldcount, newcount;
|
||||
int oldcount, newcount;
|
||||
|
||||
if (!size) size = 1;
|
||||
oldcount = get_sel_count( sel );
|
||||
newcount = (size + 0xffff) >> 16;
|
||||
wine_ldt_get_entry( sel, &entry );
|
||||
oldcount = (wine_ldt_get_limit(&entry) >> 16) + 1;
|
||||
newcount = (size + 0xffff) >> 16;
|
||||
|
||||
if (oldcount < newcount) /* We need to add selectors */
|
||||
{
|
||||
WORD index = sel >> __AHSHIFT;
|
||||
/* Check if the next selectors are free */
|
||||
if (index + newcount > LDT_SIZE) i = oldcount;
|
||||
else
|
||||
for (i = oldcount; i < newcount; i++)
|
||||
if (wine_ldt_copy.flags[index+i] & WINE_LDT_FLAGS_ALLOCATED) break;
|
||||
|
||||
if (i < newcount) /* they are not free */
|
||||
{
|
||||
SELECTOR_FreeBlock( sel );
|
||||
sel = SELECTOR_AllocArray( newcount );
|
||||
}
|
||||
else /* mark the selectors as allocated */
|
||||
{
|
||||
for (i = oldcount; i < newcount; i++)
|
||||
wine_ldt_copy.flags[index+i] |= WINE_LDT_FLAGS_ALLOCATED;
|
||||
}
|
||||
}
|
||||
else if (oldcount > newcount) /* We need to remove selectors */
|
||||
{
|
||||
SELECTOR_FreeBlock( sel + (newcount << __AHSHIFT) );
|
||||
}
|
||||
sel = wine_ldt_realloc_entries( sel, oldcount, newcount );
|
||||
if (sel) SELECTOR_SetEntries( sel, base, size, wine_ldt_get_flags(&entry) );
|
||||
return sel;
|
||||
}
|
||||
|
@ -272,7 +202,7 @@ WORD WINAPI AllocCStoDSAlias16( WORD sel )
|
|||
WORD newsel;
|
||||
LDT_ENTRY entry;
|
||||
|
||||
newsel = SELECTOR_AllocArray( 1 );
|
||||
newsel = wine_ldt_alloc_entries( 1 );
|
||||
TRACE("(%04x): returning %04x\n",
|
||||
sel, newsel );
|
||||
if (!newsel) return 0;
|
||||
|
@ -291,7 +221,7 @@ WORD WINAPI AllocDStoCSAlias16( WORD sel )
|
|||
WORD newsel;
|
||||
LDT_ENTRY entry;
|
||||
|
||||
newsel = SELECTOR_AllocArray( 1 );
|
||||
newsel = wine_ldt_alloc_entries( 1 );
|
||||
TRACE("(%04x): returning %04x\n",
|
||||
sel, newsel );
|
||||
if (!newsel) return 0;
|
||||
|
@ -395,8 +325,8 @@ BOOL16 WINAPI IsBadCodePtr16( SEGPTR lpfn )
|
|||
|
||||
sel = SELECTOROF(lpfn);
|
||||
if (!sel) return TRUE;
|
||||
if (IS_SELECTOR_FREE(sel)) return TRUE;
|
||||
wine_ldt_get_entry( sel, &entry );
|
||||
if (wine_ldt_is_empty( &entry )) return TRUE;
|
||||
/* check for code segment, ignoring conforming, read-only and accessed bits */
|
||||
if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_CODE) & 0x18) return TRUE;
|
||||
if (OFFSETOF(lpfn) > wine_ldt_get_limit(&entry)) return TRUE;
|
||||
|
@ -414,8 +344,8 @@ BOOL16 WINAPI IsBadStringPtr16( SEGPTR ptr, UINT16 size )
|
|||
|
||||
sel = SELECTOROF(ptr);
|
||||
if (!sel) return TRUE;
|
||||
if (IS_SELECTOR_FREE(sel)) return TRUE;
|
||||
wine_ldt_get_entry( sel, &entry );
|
||||
if (wine_ldt_is_empty( &entry )) return TRUE;
|
||||
/* check for data or readable code segment */
|
||||
if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE; /* system descriptor */
|
||||
if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE; /* non-readable code segment */
|
||||
|
@ -435,8 +365,8 @@ BOOL16 WINAPI IsBadHugeReadPtr16( SEGPTR ptr, DWORD size )
|
|||
|
||||
sel = SELECTOROF(ptr);
|
||||
if (!sel) return TRUE;
|
||||
if (IS_SELECTOR_FREE(sel)) return TRUE;
|
||||
wine_ldt_get_entry( sel, &entry );
|
||||
if (wine_ldt_is_empty( &entry )) return TRUE;
|
||||
/* check for data or readable code segment */
|
||||
if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE; /* system descriptor */
|
||||
if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE; /* non-readable code segment */
|
||||
|
@ -455,8 +385,8 @@ BOOL16 WINAPI IsBadHugeWritePtr16( SEGPTR ptr, DWORD size )
|
|||
|
||||
sel = SELECTOROF(ptr);
|
||||
if (!sel) return TRUE;
|
||||
if (IS_SELECTOR_FREE(sel)) return TRUE;
|
||||
wine_ldt_get_entry( sel, &entry );
|
||||
if (wine_ldt_is_empty( &entry )) return TRUE;
|
||||
/* check for writeable data segment, ignoring expand-down and accessed flags */
|
||||
if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_DATA) & ~5) return TRUE;
|
||||
if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit( &entry ))) return TRUE;
|
||||
|
@ -496,13 +426,15 @@ BOOL16 WINAPI IsBadFlatReadWritePtr16( SEGPTR ptr, DWORD size, BOOL16 bWrite )
|
|||
*/
|
||||
DWORD WINAPI MemoryRead16( WORD sel, DWORD offset, void *buffer, DWORD count )
|
||||
{
|
||||
WORD index = sel >> __AHSHIFT;
|
||||
LDT_ENTRY entry;
|
||||
DWORD limit;
|
||||
|
||||
if (!(wine_ldt_copy.flags[index] & WINE_LDT_FLAGS_ALLOCATED)) return 0;
|
||||
if (offset > wine_ldt_copy.limit[index]) return 0;
|
||||
if (offset + count > wine_ldt_copy.limit[index] + 1)
|
||||
count = wine_ldt_copy.limit[index] + 1 - offset;
|
||||
memcpy( buffer, (char *)wine_ldt_copy.base[index] + offset, count );
|
||||
wine_ldt_get_entry( sel, &entry );
|
||||
if (wine_ldt_is_empty( &entry )) return 0;
|
||||
limit = wine_ldt_get_limit( &entry );
|
||||
if (offset > limit) return 0;
|
||||
if (offset + count > limit + 1) count = limit + 1 - offset;
|
||||
memcpy( buffer, (char *)wine_ldt_get_base(&entry) + offset, count );
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -512,13 +444,15 @@ DWORD WINAPI MemoryRead16( WORD sel, DWORD offset, void *buffer, DWORD count )
|
|||
*/
|
||||
DWORD WINAPI MemoryWrite16( WORD sel, DWORD offset, void *buffer, DWORD count )
|
||||
{
|
||||
WORD index = sel >> __AHSHIFT;
|
||||
LDT_ENTRY entry;
|
||||
DWORD limit;
|
||||
|
||||
if (!(wine_ldt_copy.flags[index] & WINE_LDT_FLAGS_ALLOCATED)) return 0;
|
||||
if (offset > wine_ldt_copy.limit[index]) return 0;
|
||||
if (offset + count > wine_ldt_copy.limit[index] + 1)
|
||||
count = wine_ldt_copy.limit[index] + 1 - offset;
|
||||
memcpy( (char *)wine_ldt_copy.base[index] + offset, buffer, count );
|
||||
wine_ldt_get_entry( sel, &entry );
|
||||
if (wine_ldt_is_empty( &entry )) return 0;
|
||||
limit = wine_ldt_get_limit( &entry );
|
||||
if (offset > limit) return 0;
|
||||
if (offset + count > limit) count = limit + 1 - offset;
|
||||
memcpy( (char *)wine_ldt_get_base(&entry) + offset, buffer, count );
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,8 +64,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(thread);
|
|||
# endif /* CLONE_VM */
|
||||
#endif /* linux || HAVE_CLONE */
|
||||
|
||||
extern void SELECTOR_FreeFs(void);
|
||||
|
||||
struct thread_cleanup_info
|
||||
{
|
||||
void *stack_base;
|
||||
|
@ -88,7 +86,12 @@ void SYSDEPS_SetCurThread( TEB *teb )
|
|||
{
|
||||
#if defined(__i386__)
|
||||
/* On the i386, the current thread is in the %fs register */
|
||||
wine_set_fs( teb->teb_sel );
|
||||
LDT_ENTRY fs_entry;
|
||||
|
||||
wine_ldt_set_base( &fs_entry, teb );
|
||||
wine_ldt_set_limit( &fs_entry, 0xfff );
|
||||
wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT );
|
||||
wine_ldt_init_fs( teb->teb_sel, &fs_entry );
|
||||
#elif defined(__powerpc__)
|
||||
/* On PowerPC, the current TEB is in the gpr13 register */
|
||||
__asm__ __volatile__("mr 2, %0" : : "r" (teb));
|
||||
|
@ -142,7 +145,7 @@ static void cleanup_thread( void *ptr )
|
|||
/* copy the info structure since it is on the stack we will free */
|
||||
struct thread_cleanup_info info = *(struct thread_cleanup_info *)ptr;
|
||||
munmap( info.stack_base, info.stack_size );
|
||||
SELECTOR_FreeFs();
|
||||
wine_ldt_free_fs( wine_get_fs() );
|
||||
#ifdef HAVE__LWP_CREATE
|
||||
_lwp_exit();
|
||||
#endif
|
||||
|
@ -294,7 +297,7 @@ void SYSDEPS_ExitThread( int status )
|
|||
struct thread_cleanup_info info;
|
||||
MEMORY_BASIC_INFORMATION meminfo;
|
||||
|
||||
FreeSelector16( teb->stack_sel );
|
||||
wine_ldt_free_entries( teb->stack_sel, 1 );
|
||||
VirtualQuery( teb->stack_top, &meminfo, sizeof(meminfo) );
|
||||
info.stack_base = meminfo.AllocationBase;
|
||||
info.stack_size = meminfo.RegionSize + ((char *)teb->stack_top - (char *)meminfo.AllocationBase);
|
||||
|
|
|
@ -105,7 +105,7 @@ static BOOL THREAD_InitTEB( TEB *teb )
|
|||
teb->stack_top = (void *)~0UL;
|
||||
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
|
||||
teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
|
||||
teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT );
|
||||
teb->teb_sel = wine_ldt_alloc_fs();
|
||||
return (teb->teb_sel != 0);
|
||||
}
|
||||
|
||||
|
@ -120,8 +120,8 @@ static void THREAD_FreeTEB( TEB *teb )
|
|||
{
|
||||
TRACE("(%p) called\n", teb );
|
||||
/* Free the associated memory */
|
||||
FreeSelector16( teb->stack_sel );
|
||||
FreeSelector16( teb->teb_sel );
|
||||
wine_ldt_free_entries( teb->stack_sel, 1 );
|
||||
wine_ldt_free_fs( teb->teb_sel );
|
||||
VirtualFree( teb->stack_base, 0, MEM_RELEASE );
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ TEB *THREAD_InitStack( TEB *teb, DWORD stack_size )
|
|||
return teb;
|
||||
|
||||
error:
|
||||
FreeSelector16( teb->teb_sel );
|
||||
wine_ldt_free_fs( teb->teb_sel );
|
||||
VirtualFree( base, 0, MEM_RELEASE );
|
||||
return NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue