vwin32.c 8.09 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * VWIN32 VxD implementation
 *
 * Copyright 1998 Marcus Meissner
 * Copyright 1998 Ulrich Weigand
 * Copyright 1998 Patrik Stridvall
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 22 23 24 25 26 27 28 29 30 31
 */

#include <stdarg.h>

#include "windef.h"
#include "winbase.h"
#include "winioctl.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(vxd);

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
typedef struct tagDIOCRegs {
    DWORD   reg_EBX;
    DWORD   reg_EDX;
    DWORD   reg_ECX;
    DWORD   reg_EAX;
    DWORD   reg_EDI;
    DWORD   reg_ESI;
    DWORD   reg_Flags;
} DIOC_REGISTERS, *PDIOC_REGISTERS;

#define VWIN32_DIOC_DOS_IOCTL     1 /* This is the specified MS-DOS device I/O ctl - Interrupt 21h Function 4400h - 4411h */
#define VWIN32_DIOC_DOS_INT25     2 /* This is the Absolute Disk Read command - Interrupt 25h */
#define VWIN32_DIOC_DOS_INT26     3 /* This is the Absolute Disk Write command - Interrupt 25h */
#define VWIN32_DIOC_DOS_INT13     4 /* This is Interrupt 13h commands */
#define VWIN32_DIOC_SIMCTRLC      5 /* Simulate Ctrl-C */
#define VWIN32_DIOC_DOS_DRIVEINFO 6 /* This is Interrupt 21h Function 730X commands */

#include <pshpack1.h>
typedef struct tagMID {
    WORD  midInfoLevel;
    DWORD midSerialNum;
    BYTE  midVolLabel[11];
    BYTE  midFileSysType[8];
} MID, *PMID;
#include <poppack.h>

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
typedef void (WINAPI *CallBuiltinHandler)( CONTEXT *context, BYTE intnum );

static CallBuiltinHandler load_builtin_handler(void)
{
    static CallBuiltinHandler handler;
    static BOOL init_done;

    if (!init_done)
    {
        HMODULE mod = LoadLibraryA( "winedos.dll" );
        if (mod) handler = (void *)GetProcAddress( mod, "CallBuiltinHandler" );
        if (!handler) FIXME( "DOS calls not supported\n" );
        init_done = TRUE;
    }
    return handler;
}
74

75 76 77 78 79 80 81
/* Pop a DWORD from the 32-bit stack */
static inline DWORD stack32_pop( CONTEXT86 *context )
{
    DWORD ret = *(DWORD *)context->Esp;
    context->Esp += sizeof(DWORD);
    return ret;
}
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135

static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
{
    memset( pCxt, 0, sizeof(*pCxt) );
    /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
             will interpret 32-bit register contents as linear pointers */

    pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
    pCxt->Eax = pIn->reg_EAX;
    pCxt->Ebx = pIn->reg_EBX;
    pCxt->Ecx = pIn->reg_ECX;
    pCxt->Edx = pIn->reg_EDX;
    pCxt->Esi = pIn->reg_ESI;
    pCxt->Edi = pIn->reg_EDI;

    /* FIXME: Only partial CONTEXT86_CONTROL */

    pCxt->EFlags = pIn->reg_Flags & ~0x00020000; /* clear vm86 mode */
}

static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
{
    memset( pOut, 0, sizeof(DIOC_REGISTERS) );

    pOut->reg_EAX = pCxt->Eax;
    pOut->reg_EBX = pCxt->Ebx;
    pOut->reg_ECX = pCxt->Ecx;
    pOut->reg_EDX = pCxt->Edx;
    pOut->reg_ESI = pCxt->Esi;
    pOut->reg_EDI = pCxt->Edi;

    /* FIXME: Only partial CONTEXT86_CONTROL */
    pOut->reg_Flags = pCxt->EFlags;
}

/***********************************************************************
 *           DeviceIoControl   (VWIN32.VXD.@)
 */
BOOL WINAPI VWIN32_DeviceIoControl(DWORD dwIoControlCode,
                                   LPVOID lpvInBuffer, DWORD cbInBuffer,
                                   LPVOID lpvOutBuffer, DWORD cbOutBuffer,
                                   LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped)
{
    switch (dwIoControlCode)
    {
    case VWIN32_DIOC_DOS_IOCTL:
    case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
    case VWIN32_DIOC_DOS_INT13:
    case VWIN32_DIOC_DOS_INT25:
    case VWIN32_DIOC_DOS_INT26:
    case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
    case VWIN32_DIOC_DOS_DRIVEINFO:
        {
            CONTEXT86 cxt;
136 137
            DIOC_REGISTERS *pIn  = lpvInBuffer;
            DIOC_REGISTERS *pOut = lpvOutBuffer;
138
            BYTE intnum = 0;
139 140 141 142 143 144 145
            CallBuiltinHandler handler;

            if (!(handler = load_builtin_handler()))
            {
                pOut->reg_Flags |= 0x0001;
                return FALSE;
            }
146 147

            TRACE( "Control '%s': "
148 149
                   "eax=0x%08x, ebx=0x%08x, ecx=0x%08x, "
                   "edx=0x%08x, esi=0x%08x, edi=0x%08x\n",
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
                   (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
                   (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
                   (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" :
                   (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" :  "???",
                   pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
                   pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );

            DIOCRegs_2_CONTEXT( pIn, &cxt );

            switch (dwIoControlCode)
            {
            case VWIN32_DIOC_DOS_IOCTL: /* Call int 21h */
            case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
            case VWIN32_DIOC_DOS_DRIVEINFO:        /* Call int 21h 730x */
                intnum = 0x21;
                break;
            case VWIN32_DIOC_DOS_INT13:
                intnum = 0x13;
                break;
            case VWIN32_DIOC_DOS_INT25:
                intnum = 0x25;
                break;
            case VWIN32_DIOC_DOS_INT26:
                intnum = 0x26;
                break;
            case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
                intnum = 0x31;
                break;
            }

180
            handler( &cxt, intnum );
181 182 183 184 185 186 187 188 189
            CONTEXT_2_DIOCRegs( &cxt, pOut );
        }
        return TRUE;

    case VWIN32_DIOC_SIMCTRLC:
        FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
        return FALSE;

    default:
190
        FIXME( "Unknown Control %d\n", dwIoControlCode);
191 192 193
        return FALSE;
    }
}
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215


/***********************************************************************
 *           VxDCall   (VWIN32.VXD.@)
 *
 *  Service numbers taken from page 448 of Pietrek's "Windows 95 System
 *  Programming Secrets".  Parameters from experimentation on real Win98.
 *
 */
DWORD WINAPI VWIN32_VxDCall( DWORD service, CONTEXT86 *context )
{
    switch ( LOWORD(service) )
    {
    case 0x0000: /* GetVersion */
        {
            DWORD vers = GetVersion();
            return (LOBYTE(vers) << 8) | HIBYTE(vers);
        }
    case 0x0020: /* Get VMCPD Version */
        {
            DWORD parm = stack32_pop(context);

216
            FIXME("Get VMCPD Version(%08x): partial stub!\n", parm);
217 218 219 220 221 222 223 224 225 226 227

            /* FIXME: This is what Win98 returns, it may
             *        not be correct in all situations.
             *        It makes Bleem! happy though.
             */
            return 0x0405;
        }
    case 0x0029: /* Int31/DPMI dispatch */
        {
            DWORD callnum = stack32_pop(context);
            DWORD parm    = stack32_pop(context);
228
            CallBuiltinHandler handler;
229

230
            TRACE("Int31/DPMI dispatch(%08x)\n", callnum);
231

232 233 234 235 236 237
            if (!(handler = load_builtin_handler()))
            {
                context->EFlags |= 0x0001;
                return 0;
            }

238 239
            context->Eax = callnum;
            context->Ecx = parm;
240
            handler( context, 0x31 );
241 242 243 244 245 246 247 248
            return LOWORD(context->Eax);
        }
    case 0x002a: /* Int41 dispatch - parm = int41 service number */
        {
            DWORD callnum = stack32_pop(context);
            return callnum; /* FIXME: should really call INT_Int41Handler() */
        }
    default:
249
        FIXME("Unknown service %08x\n", service);
250 251 252
        return 0xffffffff;
    }
}