windpmi.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 566 行 · 第 1/2 页

C
566
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  DPMI function wrappers for Win386.
*
****************************************************************************/


#include <stddef.h>
#include <windows.h>
#include "winext.h"
#include "dpmi.h"

#define MAX_CACHE       48
#define MAX_SELECTORS   8192

extern DWORD    StackSize;
extern DWORD    SaveSP;
extern WORD     DataSelector;
extern WORD     StackSelector;
extern WORD     Int21Selector;
extern addr_48  CodeEntry;
extern DWORD    CodeSelectorBase;
extern DWORD    DataSelectorBase;
extern DWORD    DataHandle;
extern WORD     DPL;

#define Align64K( x ) ( ((x) + 0xffffL) & ~0xffffL )

typedef struct {
    WORD        sel;
    WORD        limit;
    DWORD       base;
    char        in_use;
} alias_cache_entry;

typedef struct memblk {
    struct memblk *next;
    DWORD       handle;
    DWORD       addr;
    DWORD       size;
} memblk;

static WORD                     WrapAround;
static WORD                     hugeIncrement;
static WORD                     firstCacheSel,lastCacheSel;
static WORD                     cacheUseCount;
static WORD                     StackCacheSel;
static DWORD                    StackBase, StackBase_64K;
static alias_cache_entry        aliasCache[ MAX_CACHE ];
static WORD                     currSelCount;
static char                     SelBitArray[MAX_SELECTORS/8];
memblk                          *MemBlkList;

static char BitMask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
/*
 * addToSelList - add selector to list of non-cached selectors
 */
static void addToSelList( WORD sel )
{
    SelBitArray[ sel >> 6 ] |= BitMask[ (sel >> 3) & 7 ];
    currSelCount++;

} /* addToSelList */

/*
 * removeFromSelList - remove selector from list of non-cached selectors
 */
static void removeFromSelList( WORD sel )
{
    SelBitArray[ sel >> 6 ] &= ~ BitMask[ (sel >> 3) & 7 ];
    currSelCount--;

} /* removeFromSelList */

/*
 * DPMIGetAliases - get alias descriptors for some memory
 */
#pragma aux DPMIGetAliases parm[dx ax] [es si] [cx] value[ax];
WORD DPMIGetAliases( DWORD offset, DWORD far *res, WORD cnt)
{
    long                rc;
    WORD                sel,i;
    DWORD               limit,base;
    alias_cache_entry   *ace;

    if( offset == 0L ) {
        (*res) = 0L;
        return( 0 );
    }

    /*
     * optimize alias requests.  If we are only asking for 1 alias,
     * then we look for a free cache entry.  The selector cache is
     * a collection of pre-allocated selectors with their access rights
     * pre-set and a default limit of 64K.  Thus, we only need to set
     * the base address and, very rarely, reset the limit (this only
     * happens when we are aliasing a chunk in the last 64K of the
     * 32-bit segment).
     */
    if( cnt == 1 ) {
        if( offset < StackBase_64K  &&  offset >= StackBase ) {
            *res = (((DWORD) StackCacheSel) << 16) + offset - StackBase;
            return( 0 );
        }
        if( cacheUseCount < MAX_CACHE ) {
            ace = &aliasCache[0];
            for( i=0;i<MAX_CACHE;i++ ) {
                if( !ace->in_use ) {
                    base = DataSelectorBase+offset;
                    if( base != ace->base ) {
                        ace->base = base;
                        DPMISetSegmentBaseAddress( ace->sel, base );
                    }
                    *res = ((DWORD) ace->sel) << 16;
                    ace->in_use = TRUE;
                    cacheUseCount++;
                    return( 0 );
                }
                ace += 1;
            }
        }
    }
    if( cnt == 0 ) {
        cnt = 1;
    }

    /*
     * get a descriptor
     */
    *res = 0L;
    rc = DPMIAllocateLDTDescriptors( cnt );
    if( rc < 0L ) {
        return( 666 );
    }
    sel = (WORD) rc;
    *res = ((DWORD) sel) << 16;
    limit = cnt * 0x10000 - 1;

    for( i=0;i<cnt;i++ ) {

        #if 0
            /*
             * We no longer restrict the limit to being 64K, since
             * Windows sets the limits of their huge selectors to be
             * for the entire linear space, not just 64K
             */
            if( limit > 0xFFFF ) {
                limit = 0xFFFF;
            }
        #endif

        /*
         * set new limit, address, and access rights
         */
        if( limit > 1024L*1024L ) {             /* 05-oct-93 */
            DPMISetDescriptorAccessRights( sel, DPL+ACCESS_DATA16BIG );
        } else {
            DPMISetDescriptorAccessRights( sel, DPL+ACCESS_DATA16 );
        }
        DPMISetSegmentBaseAddress( sel, DataSelectorBase + offset );
        DPMISetSegmentLimit( sel, limit );
        addToSelList( sel );
        sel += hugeIncrement;
        offset += 0x10000;
        limit  -= 0x10000;
    }

    return( 0 );

} /* DPMIGetAliases */

void DPMIFreeAlias( WORD sel )
{
    alias_cache_entry   *ace;

    if( sel == 0  ||  sel == StackCacheSel ) {
        return;
    }
    if( sel >= firstCacheSel && sel <= lastCacheSel ) {
        ace = &aliasCache[ (sel-firstCacheSel)/hugeIncrement ];
        if( ace->in_use ) {
            ace->in_use = FALSE;
            cacheUseCount--;
        }
        return;
    }
    removeFromSelList( sel );
    DPMIFreeLDTDescriptor( sel );

} /* DPMIFreeAlias */

WORD DPMIGetHugeAlias( DWORD offset, DWORD far *res, DWORD size )
{
    DWORD       no64k;

    no64k = Align64K( size );
    return( DPMIGetAliases( offset, res, 1+(WORD) (no64k/0x10000L) ));
}

void DPMIFreeHugeAlias( DWORD desc, DWORD size )
{
    DWORD       no64k;
    WORD        cnt,sel,i;

    sel = desc >> 16;
    if( sel == 0 ) {
        return;
    }
    no64k = Align64K( size );
    cnt = 1+(WORD) (no64k/0x10000L);
    for( i=0;i<cnt;i++ ) {
        removeFromSelList( sel );
        DPMIFreeLDTDescriptor( sel );
        sel += hugeIncrement;
    }
}

/*
 * __DPMI fns are the ones called by the 32-bit application
 */
WORD FAR PASCAL __DPMIGetAlias( DWORD offset, DWORD far *res )
{
    return( DPMIGetAliases( offset, res, 1 ) );
}
void PASCAL FAR __DPMIFreeAlias( DWORD desc )
{
    DPMIFreeAlias( desc >> 16 );
}

WORD FAR PASCAL __DPMIGetHugeAlias( DWORD offset, DWORD far *res, DWORD size )
{
    return( DPMIGetHugeAlias( offset, res, size ) );
}

void PASCAL FAR __DPMIFreeHugeAlias( DWORD desc, DWORD size )
{
    DPMIFreeHugeAlias( desc, size );
}

/*
 * setLimitAndAddr - set the limit and address of a 32-bit selector
 */
void setLimitAndAddr( WORD sel, DWORD addr, DWORD len, WORD type )
{

    DPMISetSegmentBaseAddress( sel, addr );
    --len;
    if( len >= 1024L*1024L ) {
        if( type == ACCESS_CODE ) {
            DPMISetDescriptorAccessRights( sel, DPL+ACCESS_CODE32BIG );
        } else {
            DPMISetDescriptorAccessRights( sel, DPL+ACCESS_DATA32BIG );
        }
    } else {
        if( type == ACCESS_CODE ) {
            DPMISetDescriptorAccessRights( sel, DPL+ACCESS_CODE32SMALL );
        } else {
            DPMISetDescriptorAccessRights( sel, DPL+ACCESS_DATA32SMALL );
        }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?