From ce1315382122763e8d2482955abfd4bd9f82c463 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 26 Feb 2003 20:34:45 +0000 Subject: [PATCH] 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. --- dlls/kernel/kernel_main.c | 18 +++ dlls/winedos/int31.c | 6 +- include/miscemu.h | 6 +- include/selectors.h | 6 +- include/wine/library.h | 22 +++ library/ldt.c | 325 ++++++++++++++++++++++++++++++++++---- loader/task.c | 11 -- memory/instr.c | 20 +-- memory/selector.c | 134 ++++------------ scheduler/sysdeps.c | 13 +- scheduler/thread.c | 8 +- 11 files changed, 390 insertions(+), 179 deletions(-) diff --git a/dlls/kernel/kernel_main.c b/dlls/kernel/kernel_main.c index c549e1fee47..442d059befe 100644 --- a/dlls/kernel/kernel_main.c +++ b/dlls/kernel/kernel_main.c @@ -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); diff --git a/dlls/winedos/int31.c b/dlls/winedos/int31.c index 412d3e50f0d..4e95dd1a5ff 100644 --- a/dlls/winedos/int31.c +++ b/dlls/winedos/int31.c @@ -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) ); } diff --git a/include/miscemu.h b/include/miscemu.h index 002f182a66d..0ef8287b985 100644 --- a/include/miscemu.h +++ b/include/miscemu.h @@ -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" \ diff --git a/include/selectors.h b/include/selectors.h index 68ea54b89b3..235db7bb57d 100644 --- a/include/selectors.h +++ b/include/selectors.h @@ -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)) diff --git a/include/wine/library.h b/include/wine/library.h index ee34e761984..93d61bf78a8 100644 --- a/include/wine/library.h +++ b/include/wine/library.h @@ -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 */ diff --git a/library/ldt.c b/library/ldt.c index 1d1c2aed146..1a421118bca 100644 --- a/library/ldt.c +++ b/library/ldt.c @@ -22,6 +22,7 @@ #include "config.h" #include "wine/port.h" +#include #include #include #include @@ -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__ */ diff --git a/loader/task.c b/loader/task.c index 4316614d509..f7a23acc80d 100644 --- a/loader/task.c +++ b/loader/task.c @@ -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) ) diff --git a/memory/instr.c b/memory/instr.c index f56c4885a69..74632ce7f20 100644 --- a/memory/instr.c +++ b/memory/instr.c @@ -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 } diff --git a/memory/selector.c b/memory/selector.c index a03f5a5ecf0..7de71c6bb5e 100644 --- a/memory/selector.c +++ b/memory/selector.c @@ -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; } diff --git a/scheduler/sysdeps.c b/scheduler/sysdeps.c index 5891fdd8ff4..106baa2e048 100644 --- a/scheduler/sysdeps.c +++ b/scheduler/sysdeps.c @@ -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); diff --git a/scheduler/thread.c b/scheduler/thread.c index 0f595bf164f..42329679cc2 100644 --- a/scheduler/thread.c +++ b/scheduler/thread.c @@ -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; }