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:
Alexandre Julliard 2003-02-26 20:34:45 +00:00
parent 28d65b1ac9
commit ce13153821
11 changed files with 390 additions and 179 deletions

View File

@ -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);

View File

@ -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) );
}

View File

@ -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" \

View File

@ -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))

View File

@ -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 */

View File

@ -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"
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_modify_ldt),
"b" (func),
"c" (ptr),
"d" (count) );
#endif /* __PIC__ */
: "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__
@ -135,15 +191,7 @@ 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;
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__ */

View File

@ -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) )

View File

@ -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
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}