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;
|
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
|
* KERNEL process initialisation routine
|
||||||
*/
|
*/
|
||||||
|
@ -114,6 +129,9 @@ static BOOL process_attach(void)
|
||||||
/* Create the shared heap for broken win95 native dlls */
|
/* Create the shared heap for broken win95 native dlls */
|
||||||
HeapCreate( HEAP_SHARED, 0, 0 );
|
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 */
|
/* finish the process initialisation for console bits, if needed */
|
||||||
__wine_set_signal_handler(SIGINT, CONSOLE_HandleCtrlC);
|
__wine_set_signal_handler(SIGINT, CONSOLE_HandleCtrlC);
|
||||||
|
|
||||||
|
|
|
@ -876,15 +876,17 @@ void WINAPI DOSVM_Int31Handler( CONTEXT86 *context )
|
||||||
case 0x0006: /* Get selector base address */
|
case 0x0006: /* Get selector base address */
|
||||||
TRACE( "get selector base address (0x%04x)\n", BX_reg(context) );
|
TRACE( "get selector base address (0x%04x)\n", BX_reg(context) );
|
||||||
{
|
{
|
||||||
|
LDT_ENTRY entry;
|
||||||
WORD sel = BX_reg(context);
|
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 */
|
context->Eax = 0x8022; /* invalid selector */
|
||||||
SET_CFLAG(context);
|
SET_CFLAG(context);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DWORD base = GetSelectorBase( sel );
|
void *base = wine_ldt_get_base(&entry);
|
||||||
SET_CX( context, HIWORD(base) );
|
SET_CX( context, HIWORD(base) );
|
||||||
SET_DX( context, LOWORD(base) );
|
SET_DX( context, LOWORD(base) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,11 +145,7 @@ extern char IO_pp_init(void);
|
||||||
* selector which is neither system selector nor zero.
|
* selector which is neither system selector nor zero.
|
||||||
*/
|
*/
|
||||||
#define CTX_SEG_OFF_TO_LIN(context,seg,off) \
|
#define CTX_SEG_OFF_TO_LIN(context,seg,off) \
|
||||||
(ISV86(context) ? PTR_REAL_TO_LIN((seg),(off)) : \
|
(ISV86(context) ? PTR_REAL_TO_LIN((seg),(off)) : wine_ldt_get_ptr((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)))))
|
|
||||||
|
|
||||||
#define INT_BARF(context,num) \
|
#define INT_BARF(context,num) \
|
||||||
ERR( "int%x: unknown/not implemented parameters:\n" \
|
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 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size );
|
||||||
extern void SELECTOR_FreeBlock( WORD sel );
|
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) */
|
/* Determine if sel is a system selector (i.e. not managed by Wine) */
|
||||||
#define IS_SELECTOR_SYSTEM(sel) \
|
#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) \
|
#define IS_SELECTOR_32BIT(sel) \
|
||||||
(IS_SELECTOR_SYSTEM(sel) || (wine_ldt_copy.flags[LOWORD(sel) >> 3] & WINE_LDT_FLAGS_32BIT))
|
(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 */
|
/* 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 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 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 */
|
/* the local copy of the LDT */
|
||||||
#ifdef __CYGWIN__
|
#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_32BIT 0x40 /* Segment is 32-bit (code or stack) */
|
||||||
#define WINE_LDT_FLAGS_ALLOCATED 0x80 /* Segment is allocated (no longer free) */
|
#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 */
|
/* helper functions to manipulate the LDT_ENTRY structure */
|
||||||
inline static void wine_ldt_set_base( LDT_ENTRY *ent, const void *base )
|
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;
|
if (ent->HighWord.Bits.Default_Big) ret |= WINE_LDT_FLAGS_32BIT;
|
||||||
return ret;
|
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 */
|
/* segment register access */
|
||||||
|
|
||||||
|
|
325
library/ldt.c
325
library/ldt.c
|
@ -22,6 +22,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "wine/port.h"
|
#include "wine/port.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -52,11 +53,25 @@ struct modify_ldt_s
|
||||||
unsigned int useable:1;
|
unsigned int useable:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int modify_ldt( int func, struct modify_ldt_s *ptr,
|
#ifndef SYS_set_thread_area
|
||||||
unsigned long count )
|
#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;
|
int res;
|
||||||
#ifdef __PIC__
|
|
||||||
__asm__ __volatile__( "pushl %%ebx\n\t"
|
__asm__ __volatile__( "pushl %%ebx\n\t"
|
||||||
"movl %2,%%ebx\n\t"
|
"movl %2,%%ebx\n\t"
|
||||||
"int $0x80\n\t"
|
"int $0x80\n\t"
|
||||||
|
@ -66,14 +81,20 @@ static inline int modify_ldt( int func, struct modify_ldt_s *ptr,
|
||||||
"r" (func),
|
"r" (func),
|
||||||
"c" (ptr),
|
"c" (ptr),
|
||||||
"d" (count) );
|
"d" (count) );
|
||||||
#else
|
if (res >= 0) return res;
|
||||||
__asm__ __volatile__("int $0x80"
|
errno = -res;
|
||||||
: "=a" (res)
|
return -1;
|
||||||
: "0" (SYS_modify_ldt),
|
}
|
||||||
"b" (func),
|
|
||||||
"c" (ptr),
|
static inline int set_thread_area( struct modify_ldt_s *ptr )
|
||||||
"d" (count) );
|
{
|
||||||
#endif /* __PIC__ */
|
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;
|
if (res >= 0) return res;
|
||||||
errno = -res;
|
errno = -res;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -101,32 +122,67 @@ extern int i386_set_ldt(int, union descriptor *, int);
|
||||||
/* local copy of the LDT */
|
/* local copy of the LDT */
|
||||||
struct __wine_ldt_copy wine_ldt_copy;
|
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;
|
lock_ldt = lock_func;
|
||||||
wine_ldt_set_base( entry, wine_ldt_copy.base[index] );
|
unlock_ldt = unlock_func;
|
||||||
wine_ldt_set_limit( entry, wine_ldt_copy.limit[index] );
|
|
||||||
wine_ldt_set_flags( entry, wine_ldt_copy.flags[index] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* 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;
|
int ret = 0, index = sel >> 3;
|
||||||
|
|
||||||
/* Entry 0 must not be modified; its base and limit are always 0 */
|
if (index < WINE_LDT_FIRST_ENTRY) return 0; /* cannot modify reserved entries */
|
||||||
if (!index) return 0;
|
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
|
|
||||||
|
@ -134,16 +190,8 @@ int wine_ldt_set_entry( unsigned short sel, const LDT_ENTRY *entry )
|
||||||
{
|
{
|
||||||
struct modify_ldt_s ldt_info;
|
struct modify_ldt_s ldt_info;
|
||||||
|
|
||||||
ldt_info.entry_number = index;
|
ldt_info.entry_number = index;
|
||||||
ldt_info.base_addr = (unsigned long)wine_ldt_get_base(entry);
|
fill_modify_ldt_struct( &ldt_info, 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;
|
|
||||||
|
|
||||||
if ((ret = modify_ldt(0x11, &ldt_info, sizeof(ldt_info))) < 0)
|
if ((ret = modify_ldt(0x11, &ldt_info, sizeof(ldt_info))) < 0)
|
||||||
perror( "modify_ldt" );
|
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
|
* selector access functions
|
||||||
*/
|
*/
|
||||||
#ifdef __i386__
|
|
||||||
# ifndef _MSC_VER
|
# ifndef _MSC_VER
|
||||||
/* Nothing needs to be done for MS C, it will do with inline versions from the winnt.h */
|
/* 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" )
|
__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_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" )
|
__ASM_GLOBAL_FUNC( wine_set_gs, "movl 4(%esp),%eax\n\tmovw %ax,%gs\n\tret" )
|
||||||
# endif /* defined(_MSC_VER) */
|
# endif /* defined(_MSC_VER) */
|
||||||
#endif /* defined(__i386__) */
|
|
||||||
|
#endif /* __i386__ */
|
||||||
|
|
|
@ -790,17 +790,6 @@ FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance )
|
||||||
return (FARPROC16)0;
|
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)
|
if ( (GlobalHandleToSel16(CURRENT_DS) != hInstanceSelector)
|
||||||
&& (hInstance != 0)
|
&& (hInstance != 0)
|
||||||
&& (hInstance != 0xffff) )
|
&& (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 )
|
inline static void *get_stack( CONTEXT86 *context )
|
||||||
{
|
{
|
||||||
if (ISV86(context))
|
if (ISV86(context)) return PTR_REAL_TO_LIN( context->SegSs, context->Esp );
|
||||||
return PTR_REAL_TO_LIN( context->SegSs, context->Esp );
|
return wine_ldt_get_ptr( 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) ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
@ -97,8 +92,6 @@ static BOOL INSTR_ReplaceSelector( CONTEXT86 *context, WORD *sel )
|
||||||
*sel = DOSMEM_BiosDataSeg;
|
*sel = DOSMEM_BiosDataSeg;
|
||||||
return TRUE;
|
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 */
|
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 long_addr, int segprefix, int *len )
|
||||||
{
|
{
|
||||||
int mod, rm, base, index = 0, ss = 0, seg = 0, off;
|
int mod, rm, base, index = 0, ss = 0, seg = 0, off;
|
||||||
|
LDT_ENTRY entry;
|
||||||
|
|
||||||
#define GET_VAL(val,type) \
|
#define GET_VAL(val,type) \
|
||||||
{ *val = *(type *)instr; instr += sizeof(type); *len += sizeof(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 */
|
/* Make sure the segment and offset are valid */
|
||||||
if (IS_SELECTOR_SYSTEM(seg)) return (BYTE *)(base + (index << ss));
|
if (IS_SELECTOR_SYSTEM(seg)) return (BYTE *)(base + (index << ss));
|
||||||
if (((seg & 7) != 7) || IS_SELECTOR_FREE(seg)) return NULL;
|
if ((seg & 7) != 7) return NULL;
|
||||||
if (wine_ldt_copy.limit[seg >> 3] < (base + (index << ss))) return NULL;
|
wine_ldt_get_entry( seg, &entry );
|
||||||
return (char *) MapSL( MAKESEGPTR( seg, 0 ) ) + base + (index << ss);
|
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
|
#undef GET_VAL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,39 +42,13 @@ inline static WORD get_sel_count( WORD sel )
|
||||||
return (wine_ldt_copy.limit[sel >> __AHSHIFT] >> 16) + 1;
|
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)
|
* AllocSelectorArray (KERNEL.206)
|
||||||
*/
|
*/
|
||||||
WORD WINAPI AllocSelectorArray16( WORD count )
|
WORD WINAPI AllocSelectorArray16( WORD count )
|
||||||
{
|
{
|
||||||
WORD i, sel = SELECTOR_AllocArray( count );
|
WORD i, sel = wine_ldt_alloc_entries( count );
|
||||||
|
|
||||||
if (sel)
|
if (sel)
|
||||||
{
|
{
|
||||||
|
@ -96,7 +70,7 @@ WORD WINAPI AllocSelector16( WORD sel )
|
||||||
WORD newsel, count, i;
|
WORD newsel, count, i;
|
||||||
|
|
||||||
count = sel ? get_sel_count(sel) : 1;
|
count = sel ? get_sel_count(sel) : 1;
|
||||||
newsel = SELECTOR_AllocArray( count );
|
newsel = wine_ldt_alloc_entries( count );
|
||||||
TRACE("(%04x): returning %04x\n", sel, newsel );
|
TRACE("(%04x): returning %04x\n", sel, newsel );
|
||||||
if (!newsel) return 0;
|
if (!newsel) return 0;
|
||||||
if (!sel) return newsel; /* nothing to copy */
|
if (!sel) return newsel; /* nothing to copy */
|
||||||
|
@ -115,41 +89,20 @@ WORD WINAPI AllocSelector16( WORD sel )
|
||||||
*/
|
*/
|
||||||
WORD WINAPI FreeSelector16( 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__
|
#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))
|
if (!((wine_get_fs() ^ sel) & ~3))
|
||||||
{
|
|
||||||
WARN("Freeing %%fs selector (%04x), not good.\n", wine_get_fs() );
|
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__ */
|
#endif /* __i386__ */
|
||||||
|
wine_ldt_free_entries( sel, 1 );
|
||||||
wine_ldt_set_entry( sel, &null_entry );
|
|
||||||
wine_ldt_copy.flags[sel >> __AHSHIFT] &= ~WINE_LDT_FLAGS_ALLOCATED;
|
|
||||||
return 0;
|
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
|
* SELECTOR_SetEntries
|
||||||
*
|
*
|
||||||
|
@ -185,7 +138,7 @@ WORD SELECTOR_AllocBlock( const void *base, DWORD size, unsigned char flags )
|
||||||
|
|
||||||
if (!size) return 0;
|
if (!size) return 0;
|
||||||
count = (size + 0xffff) / 0x10000;
|
count = (size + 0xffff) / 0x10000;
|
||||||
sel = SELECTOR_AllocArray( count );
|
sel = wine_ldt_alloc_entries( count );
|
||||||
if (sel) SELECTOR_SetEntries( sel, base, size, flags );
|
if (sel) SELECTOR_SetEntries( sel, base, size, flags );
|
||||||
return sel;
|
return sel;
|
||||||
}
|
}
|
||||||
|
@ -213,37 +166,14 @@ void SELECTOR_FreeBlock( WORD sel )
|
||||||
WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size )
|
WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size )
|
||||||
{
|
{
|
||||||
LDT_ENTRY entry;
|
LDT_ENTRY entry;
|
||||||
WORD i, oldcount, newcount;
|
int oldcount, newcount;
|
||||||
|
|
||||||
if (!size) size = 1;
|
if (!size) size = 1;
|
||||||
oldcount = get_sel_count( sel );
|
|
||||||
newcount = (size + 0xffff) >> 16;
|
|
||||||
wine_ldt_get_entry( sel, &entry );
|
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 */
|
sel = wine_ldt_realloc_entries( sel, oldcount, newcount );
|
||||||
{
|
|
||||||
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) );
|
|
||||||
}
|
|
||||||
if (sel) SELECTOR_SetEntries( sel, base, size, wine_ldt_get_flags(&entry) );
|
if (sel) SELECTOR_SetEntries( sel, base, size, wine_ldt_get_flags(&entry) );
|
||||||
return sel;
|
return sel;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +202,7 @@ WORD WINAPI AllocCStoDSAlias16( WORD sel )
|
||||||
WORD newsel;
|
WORD newsel;
|
||||||
LDT_ENTRY entry;
|
LDT_ENTRY entry;
|
||||||
|
|
||||||
newsel = SELECTOR_AllocArray( 1 );
|
newsel = wine_ldt_alloc_entries( 1 );
|
||||||
TRACE("(%04x): returning %04x\n",
|
TRACE("(%04x): returning %04x\n",
|
||||||
sel, newsel );
|
sel, newsel );
|
||||||
if (!newsel) return 0;
|
if (!newsel) return 0;
|
||||||
|
@ -291,7 +221,7 @@ WORD WINAPI AllocDStoCSAlias16( WORD sel )
|
||||||
WORD newsel;
|
WORD newsel;
|
||||||
LDT_ENTRY entry;
|
LDT_ENTRY entry;
|
||||||
|
|
||||||
newsel = SELECTOR_AllocArray( 1 );
|
newsel = wine_ldt_alloc_entries( 1 );
|
||||||
TRACE("(%04x): returning %04x\n",
|
TRACE("(%04x): returning %04x\n",
|
||||||
sel, newsel );
|
sel, newsel );
|
||||||
if (!newsel) return 0;
|
if (!newsel) return 0;
|
||||||
|
@ -395,8 +325,8 @@ BOOL16 WINAPI IsBadCodePtr16( SEGPTR lpfn )
|
||||||
|
|
||||||
sel = SELECTOROF(lpfn);
|
sel = SELECTOROF(lpfn);
|
||||||
if (!sel) return TRUE;
|
if (!sel) return TRUE;
|
||||||
if (IS_SELECTOR_FREE(sel)) return TRUE;
|
|
||||||
wine_ldt_get_entry( sel, &entry );
|
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 */
|
/* check for code segment, ignoring conforming, read-only and accessed bits */
|
||||||
if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_CODE) & 0x18) return TRUE;
|
if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_CODE) & 0x18) return TRUE;
|
||||||
if (OFFSETOF(lpfn) > wine_ldt_get_limit(&entry)) 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);
|
sel = SELECTOROF(ptr);
|
||||||
if (!sel) return TRUE;
|
if (!sel) return TRUE;
|
||||||
if (IS_SELECTOR_FREE(sel)) return TRUE;
|
|
||||||
wine_ldt_get_entry( sel, &entry );
|
wine_ldt_get_entry( sel, &entry );
|
||||||
|
if (wine_ldt_is_empty( &entry )) return TRUE;
|
||||||
/* check for data or readable code segment */
|
/* check for data or readable code segment */
|
||||||
if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE; /* system descriptor */
|
if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE; /* system descriptor */
|
||||||
if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE; /* non-readable code segment */
|
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);
|
sel = SELECTOROF(ptr);
|
||||||
if (!sel) return TRUE;
|
if (!sel) return TRUE;
|
||||||
if (IS_SELECTOR_FREE(sel)) return TRUE;
|
|
||||||
wine_ldt_get_entry( sel, &entry );
|
wine_ldt_get_entry( sel, &entry );
|
||||||
|
if (wine_ldt_is_empty( &entry )) return TRUE;
|
||||||
/* check for data or readable code segment */
|
/* check for data or readable code segment */
|
||||||
if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE; /* system descriptor */
|
if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE; /* system descriptor */
|
||||||
if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE; /* non-readable code segment */
|
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);
|
sel = SELECTOROF(ptr);
|
||||||
if (!sel) return TRUE;
|
if (!sel) return TRUE;
|
||||||
if (IS_SELECTOR_FREE(sel)) return TRUE;
|
|
||||||
wine_ldt_get_entry( sel, &entry );
|
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 */
|
/* check for writeable data segment, ignoring expand-down and accessed flags */
|
||||||
if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_DATA) & ~5) return TRUE;
|
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;
|
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 )
|
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;
|
wine_ldt_get_entry( sel, &entry );
|
||||||
if (offset > wine_ldt_copy.limit[index]) return 0;
|
if (wine_ldt_is_empty( &entry )) return 0;
|
||||||
if (offset + count > wine_ldt_copy.limit[index] + 1)
|
limit = wine_ldt_get_limit( &entry );
|
||||||
count = wine_ldt_copy.limit[index] + 1 - offset;
|
if (offset > limit) return 0;
|
||||||
memcpy( buffer, (char *)wine_ldt_copy.base[index] + offset, count );
|
if (offset + count > limit + 1) count = limit + 1 - offset;
|
||||||
|
memcpy( buffer, (char *)wine_ldt_get_base(&entry) + offset, count );
|
||||||
return 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 )
|
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;
|
wine_ldt_get_entry( sel, &entry );
|
||||||
if (offset > wine_ldt_copy.limit[index]) return 0;
|
if (wine_ldt_is_empty( &entry )) return 0;
|
||||||
if (offset + count > wine_ldt_copy.limit[index] + 1)
|
limit = wine_ldt_get_limit( &entry );
|
||||||
count = wine_ldt_copy.limit[index] + 1 - offset;
|
if (offset > limit) return 0;
|
||||||
memcpy( (char *)wine_ldt_copy.base[index] + offset, buffer, count );
|
if (offset + count > limit) count = limit + 1 - offset;
|
||||||
|
memcpy( (char *)wine_ldt_get_base(&entry) + offset, buffer, count );
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(thread);
|
||||||
# endif /* CLONE_VM */
|
# endif /* CLONE_VM */
|
||||||
#endif /* linux || HAVE_CLONE */
|
#endif /* linux || HAVE_CLONE */
|
||||||
|
|
||||||
extern void SELECTOR_FreeFs(void);
|
|
||||||
|
|
||||||
struct thread_cleanup_info
|
struct thread_cleanup_info
|
||||||
{
|
{
|
||||||
void *stack_base;
|
void *stack_base;
|
||||||
|
@ -88,7 +86,12 @@ void SYSDEPS_SetCurThread( TEB *teb )
|
||||||
{
|
{
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
/* On the i386, the current thread is in the %fs register */
|
/* 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__)
|
#elif defined(__powerpc__)
|
||||||
/* On PowerPC, the current TEB is in the gpr13 register */
|
/* On PowerPC, the current TEB is in the gpr13 register */
|
||||||
__asm__ __volatile__("mr 2, %0" : : "r" (teb));
|
__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 */
|
/* copy the info structure since it is on the stack we will free */
|
||||||
struct thread_cleanup_info info = *(struct thread_cleanup_info *)ptr;
|
struct thread_cleanup_info info = *(struct thread_cleanup_info *)ptr;
|
||||||
munmap( info.stack_base, info.stack_size );
|
munmap( info.stack_base, info.stack_size );
|
||||||
SELECTOR_FreeFs();
|
wine_ldt_free_fs( wine_get_fs() );
|
||||||
#ifdef HAVE__LWP_CREATE
|
#ifdef HAVE__LWP_CREATE
|
||||||
_lwp_exit();
|
_lwp_exit();
|
||||||
#endif
|
#endif
|
||||||
|
@ -294,7 +297,7 @@ void SYSDEPS_ExitThread( int status )
|
||||||
struct thread_cleanup_info info;
|
struct thread_cleanup_info info;
|
||||||
MEMORY_BASIC_INFORMATION meminfo;
|
MEMORY_BASIC_INFORMATION meminfo;
|
||||||
|
|
||||||
FreeSelector16( teb->stack_sel );
|
wine_ldt_free_entries( teb->stack_sel, 1 );
|
||||||
VirtualQuery( teb->stack_top, &meminfo, sizeof(meminfo) );
|
VirtualQuery( teb->stack_top, &meminfo, sizeof(meminfo) );
|
||||||
info.stack_base = meminfo.AllocationBase;
|
info.stack_base = meminfo.AllocationBase;
|
||||||
info.stack_size = meminfo.RegionSize + ((char *)teb->stack_top - (char *)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->stack_top = (void *)~0UL;
|
||||||
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
|
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
|
||||||
teb->StaticUnicodeString.Buffer = (PWSTR)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);
|
return (teb->teb_sel != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,8 +120,8 @@ static void THREAD_FreeTEB( TEB *teb )
|
||||||
{
|
{
|
||||||
TRACE("(%p) called\n", teb );
|
TRACE("(%p) called\n", teb );
|
||||||
/* Free the associated memory */
|
/* Free the associated memory */
|
||||||
FreeSelector16( teb->stack_sel );
|
wine_ldt_free_entries( teb->stack_sel, 1 );
|
||||||
FreeSelector16( teb->teb_sel );
|
wine_ldt_free_fs( teb->teb_sel );
|
||||||
VirtualFree( teb->stack_base, 0, MEM_RELEASE );
|
VirtualFree( teb->stack_base, 0, MEM_RELEASE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ TEB *THREAD_InitStack( TEB *teb, DWORD stack_size )
|
||||||
return teb;
|
return teb;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
FreeSelector16( teb->teb_sel );
|
wine_ldt_free_fs( teb->teb_sel );
|
||||||
VirtualFree( base, 0, MEM_RELEASE );
|
VirtualFree( base, 0, MEM_RELEASE );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue