blob: 367aae2627f7a10d0fd4e69eaa6a08a1f238aa40 [file] [log] [blame]
/*
* Selector manipulation functions
*
* Copyright 1995 Alexandre Julliard
*/
#include <string.h>
#include "windows.h"
#include "ldt.h"
#include "selectors.h"
#include "stddebug.h"
#include "debug.h"
ldt_copy_entry ldt_copy[LDT_SIZE] = { {0,0}, };
#define FIRST_LDT_ENTRY_TO_ALLOC 6
/***********************************************************************
* AllocSelectorArray (KERNEL.206)
*/
WORD AllocSelectorArray( WORD count )
{
WORD i, size = 0;
if (!count) return 0;
for (i = FIRST_LDT_ENTRY_TO_ALLOC; i < LDT_SIZE; i++)
{
if (!IS_LDT_ENTRY_FREE(i)) size = 0;
else if (++size >= count) break;
}
if (i == LDT_SIZE) return 0;
return ENTRY_TO_SELECTOR( i - size + 1 );
}
/***********************************************************************
* AllocSelector (KERNEL.175)
*/
WORD AllocSelector( WORD sel )
{
WORD newsel, count, i;
count = sel ? ((GET_SEL_LIMIT(sel) >> 16) + 1) : 1;
newsel = AllocSelectorArray( count );
dprintf_selector( stddeb, "AllocSelector(%04x): returning %04x\n",
sel, newsel );
if (!newsel) return 0;
if (!sel) return newsel; /* nothing to copy */
for (i = 0; i < count; i++)
{
ldt_entry entry;
LDT_GetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
LDT_SetEntry( SELECTOR_TO_ENTRY(newsel) + i, &entry );
}
return newsel;
}
/***********************************************************************
* FreeSelector (KERNEL.176)
*/
WORD FreeSelector( WORD sel )
{
WORD i, count;
ldt_entry entry;
dprintf_selector( stddeb, "FreeSelector(%04x)\n", sel );
if (IS_SELECTOR_FREE(sel)) return sel; /* error */
count = (GET_SEL_LIMIT(sel) >> 16) + 1;
memset( &entry, 0, sizeof(entry) ); /* clear the LDT entries */
for (i = 0; i < count; i++)
LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
return 0;
}
/***********************************************************************
* SELECTOR_SetEntries
*
* Set the LDT entries for an array of selectors.
*/
static void SELECTOR_SetEntries( WORD sel, void *base, DWORD size,
enum seg_type type, BOOL is32bit,
BOOL readonly )
{
ldt_entry entry;
WORD i, count;
/* The limit for the first selector is the whole */
/* block. The next selectors get a 64k limit. */
entry.base = (unsigned long)base;
entry.type = type;
entry.seg_32bit = is32bit;
entry.read_only = readonly;
entry.limit_in_pages = (size > 0x100000);
if (entry.limit_in_pages) entry.limit = ((size + 0xfff) >> 12) - 1;
else entry.limit = size - 1;
count = (size + 0xffff) / 0x10000;
for (i = 0; i < count; i++)
{
LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
entry.base += 0x10000;
size -= 0x10000;
entry.limit = (size > 0x10000) ? 0xffff : size-1;
entry.limit_in_pages = 0;
}
}
/***********************************************************************
* SELECTOR_ReallocArray
*
* Change the size of an allocated selector array.
*/
static WORD SELECTOR_ReallocArray( WORD sel, WORD newcount )
{
WORD i, oldcount;
ldt_entry entry;
oldcount = (GET_SEL_LIMIT(sel) >> 16) + 1;
if (oldcount < newcount) /* We need to add selectors */
{
/* Check if the next selectors are free */
for (i = oldcount; i < newcount; i++)
if (!IS_SELECTOR_FREE(sel+i)) break;
if (i < newcount)
{
FreeSelector( sel );
sel = AllocSelectorArray( newcount );
}
}
else if (oldcount > newcount) /* We need to remove selectors */
{
memset( &entry, 0, sizeof(entry) ); /* clear the LDT entries */
for (i = oldcount; i < newcount; i++)
LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
}
return sel;
}
/***********************************************************************
* SELECTOR_AllocBlock
*
* Allocate selectors for a block of linear memory.
*/
WORD SELECTOR_AllocBlock( void *base, DWORD size, enum seg_type type,
BOOL is32bit, BOOL readonly )
{
WORD sel, count;
if (!size) return 0;
count = (size + 0xffff) / 0x10000;
sel = AllocSelectorArray( count );
if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
return sel;
}
/***********************************************************************
* SELECTOR_ReallocBlock
*
* Change the size of a block of selectors.
*/
WORD SELECTOR_ReallocBlock( WORD sel, void *base, DWORD size,
enum seg_type type, BOOL is32bit, BOOL readonly )
{
WORD count;
if (!size)
{
FreeSelector( sel );
return 0;
}
count = (size + 0xffff) / 0x10000;
sel = SELECTOR_ReallocArray( sel, count );
if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
return sel;
}
/***********************************************************************
* PrestoChangoSelector (KERNEL.177)
*/
WORD PrestoChangoSelector( WORD selSrc, WORD selDst )
{
ldt_entry entry;
LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc ), &entry );
entry.type ^= SEGMENT_CODE; /* toggle the executable bit */
LDT_SetEntry( SELECTOR_TO_ENTRY( selDst ), &entry );
return selDst;
}
/***********************************************************************
* AllocCStoDSAlias (KERNEL.170)
*/
WORD AllocCStoDSAlias( WORD sel )
{
WORD newsel;
ldt_entry entry;
newsel = AllocSelectorArray( 1 );
dprintf_selector( stddeb, "AllocCStoDSAlias(%04x): returning %04x\n",
sel, newsel );
if (!newsel) return 0;
LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
entry.type = SEGMENT_DATA;
LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
return newsel;
}
/***********************************************************************
* AllocDStoCSAlias (KERNEL.171)
*/
WORD AllocDStoCSAlias( WORD sel )
{
WORD newsel;
ldt_entry entry;
newsel = AllocSelectorArray( 1 );
dprintf_selector( stddeb, "AllocDStoCSAlias(%04x): returning %04x\n",
sel, newsel );
if (!newsel) return 0;
LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
entry.type = SEGMENT_CODE;
LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
return newsel;
}
/***********************************************************************
* LongPtrAdd (KERNEL.180)
*/
void LongPtrAdd( DWORD ptr, DWORD add )
{
ldt_entry entry;
LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
entry.base += add;
LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
}
/***********************************************************************
* GetSelectorBase (KERNEL.186)
*/
DWORD GetSelectorBase( WORD sel )
{
return GET_SEL_BASE(sel);
}
/***********************************************************************
* SetSelectorBase (KERNEL.187)
*/
WORD SetSelectorBase( WORD sel, DWORD base )
{
ldt_entry entry;
LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
entry.base = base;
LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
return sel;
}
/***********************************************************************
* GetSelectorLimit (KERNEL.188)
*/
DWORD GetSelectorLimit( WORD sel )
{
return GET_SEL_LIMIT(sel);
}
/***********************************************************************
* SetSelectorLimit (KERNEL.189)
*/
WORD SetSelectorLimit( WORD sel, DWORD limit )
{
ldt_entry entry;
LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
entry.limit = limit;
LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
return sel;
}
/***********************************************************************
* SelectorAccessRights (KERNEL.196)
*/
WORD SelectorAccessRights( WORD sel, WORD op, WORD val )
{
ldt_entry entry;
LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
if (op == 0) /* get */
{
return 1 /* accessed */ |
(entry.read_only << 1) |
(entry.type << 2) |
(entry.seg_32bit << 14) |
(entry.limit_in_pages << 15);
}
else /* set */
{
entry.read_only = val & 2;
entry.type = (val >> 2) & 3;
entry.seg_32bit = val & 0x4000;
entry.limit_in_pages = val & 0x8000;
LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
return 0;
}
}
/***********************************************************************
* IsBadCodePtr (KERNEL.336)
*/
BOOL IsBadCodePtr( SEGPTR lpfn )
{
WORD sel;
ldt_entry entry;
sel = SELECTOROF(lpfn);
if (!sel) return FALSE;
if (IS_SELECTOR_FREE(sel)) return FALSE;
LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
if (entry.type != SEGMENT_CODE) return FALSE;
if (OFFSETOF(lpfn) > entry.limit) return FALSE;
return TRUE;
}
/***********************************************************************
* IsBadStringPtr (KERNEL.337)
*/
BOOL IsBadStringPtr( SEGPTR ptr, WORD size )
{
WORD sel;
ldt_entry entry;
sel = SELECTOROF(ptr);
if (!sel) return FALSE;
if (IS_SELECTOR_FREE(sel)) return FALSE;
LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
if ((entry.type == SEGMENT_CODE) && entry.read_only) return FALSE;
if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
if (OFFSETOF(ptr) + size > entry.limit) return FALSE;
return TRUE;
}
/***********************************************************************
* IsBadHugeReadPtr (KERNEL.346)
*/
BOOL IsBadHugeReadPtr( SEGPTR ptr, DWORD size )
{
WORD sel;
ldt_entry entry;
sel = SELECTOROF(ptr);
if (!sel) return FALSE;
if (IS_SELECTOR_FREE(sel)) return FALSE;
LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
if ((entry.type == SEGMENT_CODE) && entry.read_only) return FALSE;
if (OFFSETOF(ptr) + size > entry.limit) return FALSE;
return TRUE;
}
/***********************************************************************
* IsBadHugeWritePtr (KERNEL.347)
*/
BOOL IsBadHugeWritePtr( SEGPTR ptr, DWORD size )
{
WORD sel;
ldt_entry entry;
sel = SELECTOROF(ptr);
if (!sel) return FALSE;
if (IS_SELECTOR_FREE(sel)) return FALSE;
LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
if ((entry.type == SEGMENT_CODE) || entry.read_only) return FALSE;
if (OFFSETOF(ptr) + size > entry.limit) return FALSE;
return TRUE;
}
/***********************************************************************
* IsBadReadPtr (KERNEL.334)
*/
BOOL IsBadReadPtr( SEGPTR ptr, WORD size )
{
return IsBadHugeReadPtr( ptr, size );
}
/***********************************************************************
* IsBadWritePtr (KERNEL.335)
*/
BOOL IsBadWritePtr( SEGPTR ptr, WORD size )
{
return IsBadHugeWritePtr( ptr, size );
}
/***********************************************************************
* MemoryRead (TOOLHELP.78)
*/
DWORD MemoryRead( WORD sel, DWORD offset, void *buffer, DWORD count )
{
if (IS_SELECTOR_FREE(sel)) return 0;
if (offset > GET_SEL_LIMIT(sel)) return 0;
if (offset + count > GET_SEL_LIMIT(sel) + 1)
count = GET_SEL_LIMIT(sel) + 1 - offset;
memcpy( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
return count;
}
/***********************************************************************
* MemoryWrite (TOOLHELP.79)
*/
DWORD MemoryWrite( WORD sel, DWORD offset, void *buffer, DWORD count )
{
if (IS_SELECTOR_FREE(sel)) return 0;
if (offset > GET_SEL_LIMIT(sel)) return 0;
if (offset + count > GET_SEL_LIMIT(sel) + 1)
count = GET_SEL_LIMIT(sel) + 1 - offset;
memcpy( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
return count;
}