Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1 | /* |
| 2 | * DPMI 0.9 emulation |
| 3 | * |
| 4 | * Copyright 1995 Alexandre Julliard |
| 5 | */ |
| 6 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 7 | #include <unistd.h> |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 8 | #include <string.h> |
Jim Aston | 2e1cafa | 1999-03-14 16:35:05 +0000 | [diff] [blame] | 9 | #include "windef.h" |
Marcus Meissner | 219cfd8 | 1999-02-24 13:05:13 +0000 | [diff] [blame] | 10 | #include "wine/winbase16.h" |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 11 | #include "ldt.h" |
Marcus Meissner | 219cfd8 | 1999-02-24 13:05:13 +0000 | [diff] [blame] | 12 | #include "global.h" |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 13 | #include "module.h" |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 14 | #include "miscemu.h" |
Alexandre Julliard | 8bbf818 | 1996-09-13 16:50:47 +0000 | [diff] [blame] | 15 | #include "msdos.h" |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 16 | #include "task.h" |
Ulrich Weigand | f6a9361 | 1999-02-28 11:19:10 +0000 | [diff] [blame] | 17 | #include "thread.h" /* for !MZ_SUPPORTED */ |
| 18 | #include "stackframe.h" /* for !MZ_SUPPORTED */ |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 19 | #include "toolhelp.h" |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 20 | #include "selectors.h" |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 21 | #include "process.h" |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 22 | #include "callback.h" |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 23 | #include "debugtools.h" |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 24 | |
Alexandre Julliard | 383da68 | 2000-02-10 22:15:21 +0000 | [diff] [blame] | 25 | DEFAULT_DEBUG_CHANNEL(int31); |
Patrik Stridvall | b4b9fae | 1999-04-19 14:56:29 +0000 | [diff] [blame] | 26 | |
Alexandre Julliard | 8bbf818 | 1996-09-13 16:50:47 +0000 | [diff] [blame] | 27 | #define DOS_GET_DRIVE(reg) ((reg) ? (reg) - 1 : DRIVE_GetCurrentDrive()) |
| 28 | |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 29 | void CreateBPB(int drive, BYTE *data, BOOL16 limited); /* defined in int21.c */ |
Alexandre Julliard | 7ff1c41 | 1997-05-25 13:58:18 +0000 | [diff] [blame] | 30 | |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 31 | static void* lastvalloced = NULL; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 32 | |
Alexandre Julliard | d7d4fdf | 1995-12-26 15:05:24 +0000 | [diff] [blame] | 33 | /* Structure for real-mode callbacks */ |
| 34 | typedef struct |
| 35 | { |
| 36 | DWORD edi; |
| 37 | DWORD esi; |
| 38 | DWORD ebp; |
| 39 | DWORD reserved; |
| 40 | DWORD ebx; |
| 41 | DWORD edx; |
| 42 | DWORD ecx; |
| 43 | DWORD eax; |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 44 | WORD fl; |
Alexandre Julliard | d7d4fdf | 1995-12-26 15:05:24 +0000 | [diff] [blame] | 45 | WORD es; |
| 46 | WORD ds; |
| 47 | WORD fs; |
| 48 | WORD gs; |
| 49 | WORD ip; |
| 50 | WORD cs; |
| 51 | WORD sp; |
| 52 | WORD ss; |
| 53 | } REALMODECALL; |
| 54 | |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 55 | |
| 56 | |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 57 | typedef struct tagRMCB { |
| 58 | DWORD address; |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 59 | DWORD proc_ofs,proc_sel; |
| 60 | DWORD regs_ofs,regs_sel; |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 61 | struct tagRMCB *next; |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 62 | } RMCB; |
| 63 | |
| 64 | static RMCB *FirstRMCB = NULL; |
| 65 | |
Ove Kaaven | 3569371 | 1998-12-14 17:26:04 +0000 | [diff] [blame] | 66 | UINT16 DPMI_wrap_seg; |
| 67 | |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 68 | /********************************************************************** |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 69 | * DPMI_xalloc |
| 70 | * special virtualalloc, allocates lineary monoton growing memory. |
| 71 | * (the usual VirtualAlloc does not satisfy that restriction) |
| 72 | */ |
| 73 | static LPVOID |
| 74 | DPMI_xalloc(int len) { |
| 75 | LPVOID ret; |
| 76 | LPVOID oldlastv = lastvalloced; |
| 77 | |
| 78 | if (lastvalloced) { |
| 79 | int xflag = 0; |
| 80 | ret = NULL; |
| 81 | while (!ret) { |
| 82 | ret=VirtualAlloc(lastvalloced,len,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE); |
| 83 | if (!ret) |
Patrik Stridvall | a9a671d | 1999-04-25 19:01:52 +0000 | [diff] [blame] | 84 | lastvalloced = (char *) lastvalloced + 0x10000; |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 85 | /* we failed to allocate one in the first round. |
| 86 | * try non-linear |
| 87 | */ |
| 88 | if (!xflag && (lastvalloced<oldlastv)) { /* wrapped */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 89 | FIXME("failed to allocate lineary growing memory (%d bytes), using non-linear growing...\n",len); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 90 | xflag++; |
| 91 | } |
| 92 | /* if we even fail to allocate something in the next |
| 93 | * round, return NULL |
| 94 | */ |
| 95 | if ((xflag==1) && (lastvalloced >= oldlastv)) |
| 96 | xflag++; |
| 97 | if ((xflag==2) && (lastvalloced < oldlastv)) { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 98 | FIXME("failed to allocate any memory of %d bytes!\n",len); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 99 | return NULL; |
| 100 | } |
| 101 | } |
| 102 | } else |
| 103 | ret=VirtualAlloc(NULL,len,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE); |
| 104 | lastvalloced = (LPVOID)(((DWORD)ret+len+0xffff)&~0xffff); |
| 105 | return ret; |
| 106 | } |
| 107 | |
| 108 | static void |
| 109 | DPMI_xfree(LPVOID ptr) { |
| 110 | VirtualFree(ptr,0,MEM_RELEASE); |
| 111 | } |
| 112 | |
| 113 | /* FIXME: perhaps we could grow this mapped area... */ |
| 114 | static LPVOID |
| 115 | DPMI_xrealloc(LPVOID ptr,int newsize) { |
| 116 | MEMORY_BASIC_INFORMATION mbi; |
| 117 | LPVOID newptr; |
| 118 | |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 119 | newptr = DPMI_xalloc(newsize); |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 120 | if (ptr) { |
| 121 | if (!VirtualQuery(ptr,&mbi,sizeof(mbi))) { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 122 | FIXME("realloc of DPMI_xallocd region %p?\n",ptr); |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 123 | return NULL; |
| 124 | } |
| 125 | if (mbi.State == MEM_FREE) { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 126 | FIXME("realloc of DPMI_xallocd region %p?\n",ptr); |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 127 | return NULL; |
| 128 | } |
| 129 | /* We do not shrink allocated memory. most reallocs |
| 130 | * only do grows anyway |
| 131 | */ |
| 132 | if (newsize<=mbi.RegionSize) |
| 133 | return ptr; |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 134 | memcpy(newptr,ptr,mbi.RegionSize); |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 135 | DPMI_xfree(ptr); |
| 136 | } |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 137 | return newptr; |
| 138 | } |
| 139 | /********************************************************************** |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 140 | * INT_GetRealModeContext |
| 141 | */ |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 142 | static void INT_GetRealModeContext( REALMODECALL *call, CONTEXT86 *context ) |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 143 | { |
| 144 | EAX_reg(context) = call->eax; |
| 145 | EBX_reg(context) = call->ebx; |
| 146 | ECX_reg(context) = call->ecx; |
| 147 | EDX_reg(context) = call->edx; |
| 148 | ESI_reg(context) = call->esi; |
| 149 | EDI_reg(context) = call->edi; |
| 150 | EBP_reg(context) = call->ebp; |
Ove Kaaven | 99c174e | 1998-11-01 12:53:17 +0000 | [diff] [blame] | 151 | EFL_reg(context) = call->fl | V86_FLAG; |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 152 | EIP_reg(context) = call->ip; |
| 153 | ESP_reg(context) = call->sp; |
| 154 | CS_reg(context) = call->cs; |
| 155 | DS_reg(context) = call->ds; |
| 156 | ES_reg(context) = call->es; |
| 157 | FS_reg(context) = call->fs; |
| 158 | GS_reg(context) = call->gs; |
Ove Kaaven | 3569371 | 1998-12-14 17:26:04 +0000 | [diff] [blame] | 159 | SS_reg(context) = call->ss; |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 160 | } |
| 161 | |
| 162 | |
| 163 | /********************************************************************** |
| 164 | * INT_SetRealModeContext |
| 165 | */ |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 166 | static void INT_SetRealModeContext( REALMODECALL *call, CONTEXT86 *context ) |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 167 | { |
| 168 | call->eax = EAX_reg(context); |
| 169 | call->ebx = EBX_reg(context); |
| 170 | call->ecx = ECX_reg(context); |
| 171 | call->edx = EDX_reg(context); |
| 172 | call->esi = ESI_reg(context); |
| 173 | call->edi = EDI_reg(context); |
| 174 | call->ebp = EBP_reg(context); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 175 | call->fl = LOWORD(EFL_reg(context)); |
| 176 | call->ip = LOWORD(EIP_reg(context)); |
| 177 | call->sp = LOWORD(ESP_reg(context)); |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 178 | call->cs = CS_reg(context); |
| 179 | call->ds = DS_reg(context); |
| 180 | call->es = ES_reg(context); |
| 181 | call->fs = FS_reg(context); |
| 182 | call->gs = GS_reg(context); |
Ove Kaaven | 3569371 | 1998-12-14 17:26:04 +0000 | [diff] [blame] | 183 | call->ss = SS_reg(context); |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 184 | } |
| 185 | |
| 186 | |
| 187 | /********************************************************************** |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 188 | * DPMI_CallRMCBProc |
| 189 | * |
| 190 | * This routine does the hard work of calling a callback procedure. |
| 191 | */ |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 192 | static void DPMI_CallRMCBProc( CONTEXT86 *context, RMCB *rmcb, WORD flag ) |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 193 | { |
| 194 | if (IS_SELECTOR_SYSTEM( rmcb->proc_sel )) { |
| 195 | /* Wine-internal RMCB, call directly */ |
| 196 | ((RMCBPROC)rmcb->proc_ofs)(context); |
| 197 | } else { |
| 198 | #ifdef __i386__ |
| 199 | UINT16 ss,es; |
| 200 | DWORD edi; |
| 201 | |
| 202 | INT_SetRealModeContext((REALMODECALL *)PTR_SEG_OFF_TO_LIN( rmcb->regs_sel, rmcb->regs_ofs ), context); |
| 203 | ss = SELECTOR_AllocBlock( DOSMEM_MemoryBase(0) + (DWORD)(SS_reg(context)<<4), 0x10000, SEGMENT_DATA, FALSE, FALSE ); |
| 204 | |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 205 | FIXME("untested!\n"); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 206 | |
| 207 | /* The called proc ends with an IRET, and takes these parameters: |
| 208 | * DS:ESI = pointer to real-mode SS:SP |
| 209 | * ES:EDI = pointer to real-mode call structure |
| 210 | * It returns: |
| 211 | * ES:EDI = pointer to real-mode call structure (may be a copy) |
| 212 | * It is the proc's responsibility to change the return CS:IP in the |
| 213 | * real-mode call structure. */ |
| 214 | if (flag & 1) { |
| 215 | /* 32-bit DPMI client */ |
Marcus Meissner | 60729af | 2000-05-24 21:02:00 +0000 | [diff] [blame] | 216 | #if HAVE_FIXED_BROKEN_ASSEMBLER_BELOW |
Patrik Stridvall | 330cd69 | 2000-06-03 20:43:06 +0000 | [diff] [blame] | 217 | int _clobber; |
Patrik Stridvall | a9a671d | 1999-04-25 19:01:52 +0000 | [diff] [blame] | 218 | __asm__ __volatile__( |
| 219 | "pushl %%es\n" |
| 220 | "pushl %%ds\n" |
| 221 | "pushfl\n" |
Marcus Meissner | 60729af | 2000-05-24 21:02:00 +0000 | [diff] [blame] | 222 | "movl %5,%%es\n" /* BAD: we are pushing potential stack |
| 223 | * parameters on an already modified |
| 224 | * stack |
| 225 | */ |
Patrik Stridvall | a9a671d | 1999-04-25 19:01:52 +0000 | [diff] [blame] | 226 | "movl %4,%%ds\n" |
| 227 | "lcall %3\n" |
| 228 | "popl %%ds\n" |
| 229 | "movl %%es,%0\n" |
| 230 | "popl %%es\n" |
Marcus Meissner | 2503e7e | 1999-03-09 17:27:52 +0000 | [diff] [blame] | 231 | : "=g" (es), "=D" (edi), "=S" (_clobber) |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 232 | : "m" (rmcb->proc_ofs), |
| 233 | "g" (ss), "g" (rmcb->regs_sel), |
Marcus Meissner | 2503e7e | 1999-03-09 17:27:52 +0000 | [diff] [blame] | 234 | "S" (ESP_reg(context)), "1" (rmcb->regs_ofs) |
| 235 | : "ecx", "edx", "ebp" ); |
Marcus Meissner | 60729af | 2000-05-24 21:02:00 +0000 | [diff] [blame] | 236 | /* BAD: uses too much registers which is starving the register |
| 237 | * alloc stage of gcc, especially in -fPIC. |
| 238 | */ |
| 239 | #else |
| 240 | FIXME("32 bit DPMI client unsupported.\n"); |
| 241 | #endif |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 242 | } else { |
| 243 | /* 16-bit DPMI client */ |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 244 | CONTEXT86 ctx = *context; |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 245 | CS_reg(&ctx) = rmcb->proc_sel; |
| 246 | EIP_reg(&ctx) = rmcb->proc_ofs; |
| 247 | DS_reg(&ctx) = ss; |
| 248 | ESI_reg(&ctx) = ESP_reg(context); |
| 249 | ES_reg(&ctx) = rmcb->regs_sel; |
| 250 | EDI_reg(&ctx) = rmcb->regs_ofs; |
| 251 | Callbacks->CallRegisterShortProc(&ctx, 2); |
| 252 | es = ES_reg(&ctx); |
| 253 | edi = EDI_reg(&ctx); |
| 254 | } |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 255 | SELECTOR_FreeBlock(ss, 1); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 256 | INT_GetRealModeContext((REALMODECALL*)PTR_SEG_OFF_TO_LIN( es, edi ), context); |
| 257 | #else |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 258 | ERR("RMCBs only implemented for i386\n"); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 259 | #endif |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | |
| 264 | /********************************************************************** |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 265 | * DPMI_CallRMProc |
| 266 | * |
| 267 | * This routine does the hard work of calling a real mode procedure. |
| 268 | */ |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 269 | int DPMI_CallRMProc( CONTEXT86 *context, LPWORD stack, int args, int iret ) |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 270 | { |
| 271 | LPWORD stack16; |
James Juran | c2a1063 | 1999-01-28 16:33:44 +0000 | [diff] [blame] | 272 | #ifndef MZ_SUPPORTED |
James Juran | c2a1063 | 1999-01-28 16:33:44 +0000 | [diff] [blame] | 273 | WORD sel; |
| 274 | SEGPTR seg_addr; |
| 275 | #endif /* !MZ_SUPPORTED */ |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 276 | LPVOID addr = NULL; /* avoid gcc warning */ |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 277 | TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() ); |
| 278 | NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL; |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 279 | RMCB *CurrRMCB; |
| 280 | int alloc = 0, already = 0; |
Ove Kaaven | e9251b0 | 1999-05-17 16:05:16 +0000 | [diff] [blame] | 281 | BYTE *code; |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 282 | |
| 283 | GlobalUnlock16( GetCurrentTask() ); |
| 284 | |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 285 | TRACE("EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n", |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 286 | EAX_reg(context), EBX_reg(context), ECX_reg(context), EDX_reg(context) ); |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 287 | TRACE("ESI=%08lx EDI=%08lx ES=%04lx DS=%04lx CS:IP=%04lx:%04x, %d WORD arguments, %s\n", |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 288 | ESI_reg(context), EDI_reg(context), ES_reg(context), DS_reg(context), |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 289 | CS_reg(context), LOWORD(EIP_reg(context)), args, iret?"IRET":"FAR" ); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 290 | |
| 291 | callrmproc_again: |
| 292 | |
Ove Kaaven | e9251b0 | 1999-05-17 16:05:16 +0000 | [diff] [blame] | 293 | /* there might be some code that just jumps to RMCBs or the like, |
| 294 | in which case following the jumps here might get us to a shortcut */ |
| 295 | code = CTX_SEG_OFF_TO_LIN(context, CS_reg(context), EIP_reg(context)); |
| 296 | switch (*code) { |
| 297 | case 0xe9: /* JMP NEAR */ |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 298 | EIP_reg(context) += 3 + *(WORD *)(code+1); |
Ove Kaaven | e9251b0 | 1999-05-17 16:05:16 +0000 | [diff] [blame] | 299 | /* yeah, I know these gotos don't look good... */ |
| 300 | goto callrmproc_again; |
| 301 | case 0xea: /* JMP FAR */ |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 302 | EIP_reg(context) = *(WORD *)(code+1); |
Ove Kaaven | e9251b0 | 1999-05-17 16:05:16 +0000 | [diff] [blame] | 303 | CS_reg(context) = *(WORD *)(code+3); |
| 304 | /* ...but since the label is there anyway... */ |
| 305 | goto callrmproc_again; |
| 306 | case 0xeb: /* JMP SHORT */ |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 307 | EIP_reg(context) += 2 + *(signed char *)(code+1); |
Ove Kaaven | e9251b0 | 1999-05-17 16:05:16 +0000 | [diff] [blame] | 308 | /* ...because of other gotos below, so... */ |
| 309 | goto callrmproc_again; |
| 310 | } |
| 311 | |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 312 | /* shortcut for chaining to internal interrupt handlers */ |
| 313 | if ((CS_reg(context) == 0xF000) && iret) { |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 314 | return INT_RealModeInterrupt( LOWORD(EIP_reg(context))/4, context); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 315 | } |
| 316 | |
| 317 | /* shortcut for RMCBs */ |
| 318 | CurrRMCB = FirstRMCB; |
| 319 | |
| 320 | while (CurrRMCB && (HIWORD(CurrRMCB->address) != CS_reg(context))) |
| 321 | CurrRMCB = CurrRMCB->next; |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 322 | |
| 323 | #ifdef MZ_SUPPORTED |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 324 | if (!(CurrRMCB || pModule->lpDosTask)) { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 325 | FIXME("DPMI real-mode call using DOS VM task system, not fully tested!\n"); |
| 326 | TRACE("creating VM86 task\n"); |
Ulrich Weigand | f6a9361 | 1999-02-28 11:19:10 +0000 | [diff] [blame] | 327 | if (!MZ_InitTask( MZ_AllocDPMITask( pModule->self ) )) { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 328 | ERR("could not setup VM86 task\n"); |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 329 | return 1; |
| 330 | } |
| 331 | } |
Patrik Stridvall | 410d899 | 1999-09-29 10:23:18 +0000 | [diff] [blame] | 332 | #endif |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 333 | if (!already) { |
Patrik Stridvall | 410d899 | 1999-09-29 10:23:18 +0000 | [diff] [blame] | 334 | #ifdef MZ_SUPPORTED |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 335 | if (!SS_reg(context)) { |
| 336 | alloc = 1; /* allocate default stack */ |
Ove Kaaven | 3569371 | 1998-12-14 17:26:04 +0000 | [diff] [blame] | 337 | stack16 = addr = DOSMEM_GetBlock( pModule->self, 64, (UINT16 *)&(SS_reg(context)) ); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 338 | ESP_reg(context) = 64-2; |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 339 | stack16 += 32-1; |
| 340 | if (!addr) { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 341 | ERR("could not allocate default stack\n"); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 342 | return 1; |
| 343 | } |
| 344 | } else { |
| 345 | stack16 = CTX_SEG_OFF_TO_LIN(context, SS_reg(context), ESP_reg(context)); |
| 346 | } |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 347 | ESP_reg(context) -= (args + (iret?1:0)) * sizeof(WORD); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 348 | #else |
Patrik Stridvall | 1ed4ecf | 1999-06-26 14:58:24 +0000 | [diff] [blame] | 349 | stack16 = (LPWORD) CURRENT_STACK16; |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 350 | #endif |
| 351 | stack16 -= args; |
| 352 | if (args) memcpy(stack16, stack, args*sizeof(WORD) ); |
| 353 | /* push flags if iret */ |
| 354 | if (iret) { |
| 355 | stack16--; args++; |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 356 | *stack16 = LOWORD(EFL_reg(context)); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 357 | } |
| 358 | #ifdef MZ_SUPPORTED |
| 359 | /* push return address (return to interrupt wrapper) */ |
Ove Kaaven | 3569371 | 1998-12-14 17:26:04 +0000 | [diff] [blame] | 360 | *(--stack16) = DPMI_wrap_seg; |
| 361 | *(--stack16) = 0; |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 362 | /* adjust stack */ |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 363 | ESP_reg(context) -= 2*sizeof(WORD); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 364 | #endif |
| 365 | already = 1; |
| 366 | } |
| 367 | |
| 368 | if (CurrRMCB) { |
| 369 | /* RMCB call, invoke protected-mode handler directly */ |
| 370 | DPMI_CallRMCBProc(context, CurrRMCB, pModule->lpDosTask?pModule->lpDosTask->dpmi_flag:0); |
| 371 | /* check if we returned to where we thought we would */ |
Ove Kaaven | 3569371 | 1998-12-14 17:26:04 +0000 | [diff] [blame] | 372 | if ((CS_reg(context) != DPMI_wrap_seg) || |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 373 | (LOWORD(EIP_reg(context)) != 0)) { |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 374 | /* we need to continue at different address in real-mode space, |
| 375 | so we need to set it all up for real mode again */ |
| 376 | goto callrmproc_again; |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 377 | } |
| 378 | } else { |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 379 | #ifdef MZ_SUPPORTED |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 380 | #if 0 /* this was probably unnecessary */ |
| 381 | /* push call address */ |
| 382 | *(--stack16) = CS_reg(context); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 383 | *(--stack16) = LOWORD(EIP_reg(context)); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 384 | /* adjust stack */ |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 385 | ESP_reg(context) -= 2*sizeof(WORD); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 386 | /* set initial CS:IP to the wrapper's "lret" */ |
Ove Kaaven | 3569371 | 1998-12-14 17:26:04 +0000 | [diff] [blame] | 387 | CS_reg(context) = DPMI_wrap_seg; |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 388 | EIP_reg(context) = 2; |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 389 | #endif |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 390 | TRACE("entering real mode...\n"); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 391 | DOSVM_Enter( context ); |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 392 | TRACE("returned from real-mode call\n"); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 393 | #else |
| 394 | addr = CTX_SEG_OFF_TO_LIN(context, CS_reg(context), EIP_reg(context)); |
| 395 | sel = SELECTOR_AllocBlock( addr, 0x10000, SEGMENT_CODE, FALSE, FALSE ); |
| 396 | seg_addr = PTR_SEG_OFF_TO_SEGPTR( sel, 0 ); |
| 397 | |
| 398 | CS_reg(context) = HIWORD(seg_addr); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 399 | EIP_reg(context) = LOWORD(seg_addr); |
Patrik Stridvall | 1ed4ecf | 1999-06-26 14:58:24 +0000 | [diff] [blame] | 400 | EBP_reg(context) = OFFSETOF( NtCurrentTeb()->cur_stack ) |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 401 | + (WORD)&((STACK16FRAME*)0)->bp; |
| 402 | Callbacks->CallRegisterShortProc(context, args*sizeof(WORD)); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 403 | SELECTOR_FreeBlock(sel, 1); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 404 | #endif |
| 405 | } |
| 406 | if (alloc) DOSMEM_FreeBlock( pModule->self, addr ); |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 407 | return 0; |
| 408 | } |
| 409 | |
| 410 | |
| 411 | /********************************************************************** |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 412 | * CallRMInt |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 413 | */ |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 414 | static void CallRMInt( CONTEXT86 *context ) |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 415 | { |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 416 | CONTEXT86 realmode_ctx; |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 417 | FARPROC16 rm_int = INT_GetRMHandler( BL_reg(context) ); |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 418 | REALMODECALL *call = (REALMODECALL *)PTR_SEG_OFF_TO_LIN( ES_reg(context), |
| 419 | DI_reg(context) ); |
| 420 | INT_GetRealModeContext( call, &realmode_ctx ); |
| 421 | |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 422 | /* we need to check if a real-mode program has hooked the interrupt */ |
| 423 | if (HIWORD(rm_int)!=0xF000) { |
| 424 | /* yup, which means we need to switch to real mode... */ |
| 425 | CS_reg(&realmode_ctx) = HIWORD(rm_int); |
| 426 | EIP_reg(&realmode_ctx) = LOWORD(rm_int); |
| 427 | if (DPMI_CallRMProc( &realmode_ctx, NULL, 0, TRUE)) |
| 428 | SET_CFLAG(context); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 429 | } else { |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 430 | RESET_CFLAG(context); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 431 | /* use the IP we have instead of BL_reg, in case some apps |
| 432 | decide to move interrupts around for whatever reason... */ |
| 433 | if (INT_RealModeInterrupt( LOWORD(rm_int)/4, &realmode_ctx )) |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 434 | SET_CFLAG(context); |
| 435 | if (EFL_reg(context)&1) { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 436 | FIXME("%02x: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n", |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 437 | BL_reg(context), EAX_reg(&realmode_ctx), EBX_reg(&realmode_ctx), |
| 438 | ECX_reg(&realmode_ctx), EDX_reg(&realmode_ctx)); |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 439 | FIXME(" ESI=%08lx EDI=%08lx DS=%04lx ES=%04lx\n", |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 440 | ESI_reg(&realmode_ctx), EDI_reg(&realmode_ctx), |
| 441 | DS_reg(&realmode_ctx), ES_reg(&realmode_ctx) ); |
| 442 | } |
Alexandre Julliard | dadf78f | 1998-05-17 17:13:43 +0000 | [diff] [blame] | 443 | } |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 444 | INT_SetRealModeContext( call, &realmode_ctx ); |
| 445 | } |
| 446 | |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 447 | |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 448 | static void CallRMProc( CONTEXT86 *context, int iret ) |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 449 | { |
| 450 | REALMODECALL *p = (REALMODECALL *)PTR_SEG_OFF_TO_LIN( ES_reg(context), DI_reg(context) ); |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 451 | CONTEXT86 context16; |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 452 | |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 453 | TRACE("RealModeCall: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n", |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 454 | p->eax, p->ebx, p->ecx, p->edx); |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 455 | TRACE(" ESI=%08lx EDI=%08lx ES=%04x DS=%04x CS:IP=%04x:%04x, %d WORD arguments, %s\n", |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 456 | p->esi, p->edi, p->es, p->ds, p->cs, p->ip, CX_reg(context), iret?"IRET":"FAR" ); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 457 | |
| 458 | if (!(p->cs) && !(p->ip)) { /* remove this check |
| 459 | if Int21/6501 case map function |
| 460 | has been implemented */ |
| 461 | SET_CFLAG(context); |
| 462 | return; |
| 463 | } |
| 464 | INT_GetRealModeContext(p, &context16); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 465 | DPMI_CallRMProc( &context16, ((LPWORD)PTR_SEG_OFF_TO_LIN(SS_reg(context), LOWORD(ESP_reg(context))))+3, |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 466 | CX_reg(context), iret ); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 467 | INT_SetRealModeContext(p, &context16); |
| 468 | } |
| 469 | |
| 470 | |
Marcus Meissner | de43ef4 | 1999-02-28 19:56:59 +0000 | [diff] [blame] | 471 | static void WINAPI WINE_UNUSED RMCallbackProc( RMCB *rmcb ) |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 472 | { |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 473 | /* This routine should call DPMI_CallRMCBProc, but we don't have the |
| 474 | register structure available - this is easily fixed by going through |
| 475 | a Win16 register relay instead of calling RMCallbackProc "directly", |
| 476 | but I won't bother at this time. */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 477 | FIXME("not properly supported on your architecture!\n"); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 478 | } |
| 479 | |
| 480 | static RMCB *DPMI_AllocRMCB( void ) |
| 481 | { |
| 482 | RMCB *NewRMCB = HeapAlloc(GetProcessHeap(), 0, sizeof(RMCB)); |
| 483 | UINT16 uParagraph; |
| 484 | |
| 485 | if (NewRMCB) |
| 486 | { |
| 487 | #ifdef MZ_SUPPORTED |
| 488 | LPVOID RMCBmem = DOSMEM_GetBlock(0, 4, &uParagraph); |
| 489 | LPBYTE p = RMCBmem; |
| 490 | |
| 491 | *p++ = 0xcd; /* RMCB: */ |
| 492 | *p++ = 0x31; /* int $0x31 */ |
| 493 | /* it is the called procedure's task to change the return CS:EIP |
| 494 | the DPMI 0.9 spec states that if it doesn't, it will be called again */ |
| 495 | *p++ = 0xeb; |
| 496 | *p++ = 0xfc; /* jmp RMCB */ |
Ulrich Weigand | 0121ac1 | 2000-06-07 02:02:56 +0000 | [diff] [blame] | 497 | #elif defined(__i386__) |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 498 | LPVOID RMCBmem = DOSMEM_GetBlock(0, 15, &uParagraph); |
| 499 | LPBYTE p = RMCBmem; |
| 500 | |
| 501 | *p++ = 0x68; /* pushl */ |
| 502 | *(LPVOID *)p = NewRMCB; |
| 503 | p+=4; |
| 504 | *p++ = 0x9a; /* lcall */ |
| 505 | *(FARPROC16 *)p = (FARPROC16)RMCallbackProc; /* FIXME: register relay */ |
| 506 | p+=4; |
Alexandre Julliard | 916f975 | 2000-02-26 16:51:13 +0000 | [diff] [blame] | 507 | *(WORD *)p = __get_cs(); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 508 | p+=2; |
| 509 | *p++=0xc3; /* lret (FIXME?) */ |
Ulrich Weigand | 0121ac1 | 2000-06-07 02:02:56 +0000 | [diff] [blame] | 510 | #else |
| 511 | uParagraph = 0; |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 512 | #endif |
| 513 | NewRMCB->address = MAKELONG(0, uParagraph); |
| 514 | NewRMCB->next = FirstRMCB; |
| 515 | FirstRMCB = NewRMCB; |
| 516 | } |
| 517 | return NewRMCB; |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 518 | } |
| 519 | |
| 520 | |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 521 | static void AllocRMCB( CONTEXT86 *context ) |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 522 | { |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 523 | RMCB *NewRMCB = DPMI_AllocRMCB(); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 524 | |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 525 | TRACE("Function to call: %04x:%04x\n", (WORD)DS_reg(context), SI_reg(context) ); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 526 | |
| 527 | if (NewRMCB) |
| 528 | { |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 529 | /* FIXME: if 32-bit DPMI client, use ESI and EDI */ |
| 530 | NewRMCB->proc_ofs = SI_reg(context); |
| 531 | NewRMCB->proc_sel = DS_reg(context); |
| 532 | NewRMCB->regs_ofs = DI_reg(context); |
| 533 | NewRMCB->regs_sel = ES_reg(context); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 534 | SET_LOWORD( ECX_reg(context), HIWORD(NewRMCB->address) ); |
| 535 | SET_LOWORD( EDX_reg(context), LOWORD(NewRMCB->address) ); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 536 | } |
| 537 | else |
| 538 | { |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 539 | SET_LOWORD( EAX_reg(context), 0x8015 ); /* callback unavailable */ |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 540 | SET_CFLAG(context); |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 545 | FARPROC16 WINAPI DPMI_AllocInternalRMCB( RMCBPROC proc ) |
| 546 | { |
| 547 | RMCB *NewRMCB = DPMI_AllocRMCB(); |
| 548 | |
| 549 | if (NewRMCB) { |
| 550 | NewRMCB->proc_ofs = (DWORD)proc; |
| 551 | NewRMCB->proc_sel = 0; |
| 552 | NewRMCB->regs_ofs = 0; |
| 553 | NewRMCB->regs_sel = 0; |
| 554 | return (FARPROC16)(NewRMCB->address); |
| 555 | } |
| 556 | return NULL; |
| 557 | } |
| 558 | |
| 559 | |
| 560 | static int DPMI_FreeRMCB( DWORD address ) |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 561 | { |
| 562 | RMCB *CurrRMCB = FirstRMCB; |
| 563 | RMCB *PrevRMCB = NULL; |
| 564 | |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 565 | while (CurrRMCB && (CurrRMCB->address != address)) |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 566 | { |
| 567 | PrevRMCB = CurrRMCB; |
| 568 | CurrRMCB = CurrRMCB->next; |
| 569 | } |
| 570 | if (CurrRMCB) |
| 571 | { |
| 572 | if (PrevRMCB) |
| 573 | PrevRMCB->next = CurrRMCB->next; |
| 574 | else |
| 575 | FirstRMCB = CurrRMCB->next; |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 576 | DOSMEM_FreeBlock(0, DOSMEM_MapRealToLinear(CurrRMCB->address)); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 577 | HeapFree(GetProcessHeap(), 0, CurrRMCB); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 578 | return 0; |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 579 | } |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 580 | return 1; |
| 581 | } |
| 582 | |
| 583 | |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 584 | static void FreeRMCB( CONTEXT86 *context ) |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 585 | { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 586 | FIXME("callback address: %04x:%04x\n", |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 587 | CX_reg(context), DX_reg(context)); |
| 588 | |
| 589 | if (DPMI_FreeRMCB(MAKELONG(DX_reg(context), CX_reg(context)))) { |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 590 | SET_LOWORD( EAX_reg(context), 0x8024 ); /* invalid callback address */ |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 591 | SET_CFLAG(context); |
| 592 | } |
| 593 | } |
| 594 | |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 595 | |
| 596 | void WINAPI DPMI_FreeInternalRMCB( FARPROC16 proc ) |
| 597 | { |
| 598 | DPMI_FreeRMCB( (DWORD)proc ); |
| 599 | } |
| 600 | |
| 601 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 602 | #ifdef MZ_SUPPORTED |
| 603 | /* (see loader/dos/module.c, function MZ_InitDPMI) */ |
| 604 | |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 605 | static void StartPM( CONTEXT86 *context, LPDOSTASK lpDosTask ) |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 606 | { |
| 607 | char *base = DOSMEM_MemoryBase(0); |
| 608 | UINT16 cs, ss, ds, es; |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 609 | CONTEXT86 pm_ctx; |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 610 | DWORD psp_ofs = (DWORD)(lpDosTask->psp_seg<<4); |
| 611 | PDB16 *psp = (PDB16 *)(base + psp_ofs); |
| 612 | HANDLE16 env_seg = psp->environment; |
| 613 | int is32; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 614 | |
| 615 | RESET_CFLAG(context); |
| 616 | lpDosTask->dpmi_flag = AX_reg(context); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 617 | is32 = lpDosTask->dpmi_flag & 1; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 618 | /* our mode switch wrapper have placed the desired CS into DX */ |
| 619 | cs = SELECTOR_AllocBlock( base + (DWORD)(DX_reg(context)<<4), 0x10000, SEGMENT_CODE, FALSE, FALSE ); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 620 | /* due to a flaw in some CPUs (at least mine), it is best to mark stack segments as 32-bit if they |
| 621 | can be used in 32-bit code. Otherwise, these CPUs may not set the high word of esp during a |
| 622 | ring transition (from kernel code) to the 16-bit stack, and this causes trouble if executing |
| 623 | 32-bit code using this stack. */ |
| 624 | ss = SELECTOR_AllocBlock( base + (DWORD)(SS_reg(context)<<4), 0x10000, SEGMENT_DATA, is32, FALSE ); |
| 625 | /* do the same for the data segments, just in case */ |
| 626 | if (DS_reg(context) == SS_reg(context)) ds = ss; |
| 627 | else ds = SELECTOR_AllocBlock( base + (DWORD)(DS_reg(context)<<4), 0x10000, SEGMENT_DATA, is32, FALSE ); |
| 628 | es = SELECTOR_AllocBlock( base + psp_ofs, 0x100, SEGMENT_DATA, is32, FALSE ); |
| 629 | /* convert environment pointer, as the spec says, but we're a bit lazy about the size here... */ |
| 630 | psp->environment = SELECTOR_AllocBlock( base + (DWORD)(env_seg<<4), |
| 631 | 0x10000, SEGMENT_DATA, FALSE, FALSE ); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 632 | |
| 633 | pm_ctx = *context; |
| 634 | CS_reg(&pm_ctx) = lpDosTask->dpmi_sel; |
| 635 | /* our mode switch wrapper expects the new CS in DX, and the new SS in AX */ |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 636 | EAX_reg(&pm_ctx) = ss; |
| 637 | EDX_reg(&pm_ctx) = cs; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 638 | DS_reg(&pm_ctx) = ds; |
| 639 | ES_reg(&pm_ctx) = es; |
| 640 | FS_reg(&pm_ctx) = 0; |
| 641 | GS_reg(&pm_ctx) = 0; |
| 642 | |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 643 | TRACE("DOS program is now entering protected mode\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 644 | Callbacks->CallRegisterShortProc(&pm_ctx, 0); |
| 645 | |
| 646 | /* in the current state of affairs, we won't ever actually return here... */ |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 647 | /* we should have int21/ah=4c do it someday, though... */ |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 648 | |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 649 | SELECTOR_FreeBlock(psp->environment, 1); |
| 650 | psp->environment = env_seg; |
| 651 | SELECTOR_FreeBlock(es, 1); |
| 652 | if (ds != ss) SELECTOR_FreeBlock(ds, 1); |
| 653 | SELECTOR_FreeBlock(ss, 1); |
| 654 | SELECTOR_FreeBlock(cs, 1); |
| 655 | } |
| 656 | |
| 657 | /* DPMI Raw Mode Switch handler */ |
| 658 | |
Alexandre Julliard | a1089c5 | 1999-08-01 12:51:55 +0000 | [diff] [blame] | 659 | #if 0 |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 660 | void WINAPI DPMI_RawModeSwitch( SIGCONTEXT *context ) |
| 661 | { |
| 662 | LPDOSTASK lpDosTask = MZ_Current(); |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 663 | CONTEXT86 rm_ctx; |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 664 | int ret; |
| 665 | |
| 666 | if (!lpDosTask) { |
| 667 | /* we could probably start a DPMI-only dosmod task here, but I doubt |
| 668 | anything other than real DOS apps want to call raw mode switch */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 669 | ERR("attempting raw mode switch without DOS task!\n"); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 670 | ExitProcess(1); |
| 671 | } |
| 672 | /* initialize real-mode context as per spec */ |
| 673 | memset(&rm_ctx, 0, sizeof(rm_ctx)); |
| 674 | DS_reg(&rm_ctx) = AX_sig(context); |
| 675 | ES_reg(&rm_ctx) = CX_sig(context); |
| 676 | SS_reg(&rm_ctx) = DX_sig(context); |
| 677 | ESP_reg(&rm_ctx) = EBX_sig(context); |
| 678 | CS_reg(&rm_ctx) = SI_sig(context); |
| 679 | EIP_reg(&rm_ctx) = EDI_sig(context); |
| 680 | EBP_reg(&rm_ctx) = EBP_sig(context); |
| 681 | FS_reg(&rm_ctx) = 0; |
| 682 | GS_reg(&rm_ctx) = 0; |
| 683 | EFL_reg(&rm_ctx) = EFL_sig(context); /* at least we need the IF flag */ |
| 684 | |
| 685 | /* enter real mode again */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 686 | TRACE("re-entering real mode at %04lx:%04lx\n", |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 687 | CS_reg(&rm_ctx),EIP_reg(&rm_ctx)); |
| 688 | ret = DOSVM_Enter( &rm_ctx ); |
| 689 | /* when the real-mode stuff call its mode switch address, |
| 690 | DOSVM_Enter will return and we will continue here */ |
| 691 | |
| 692 | if (ret<0) { |
| 693 | /* if the sync was lost, there's no way to recover */ |
| 694 | ExitProcess(1); |
| 695 | } |
| 696 | |
| 697 | /* alter protected-mode context as per spec */ |
| 698 | DS_sig(context) = AX_reg(&rm_ctx); |
| 699 | ES_sig(context) = CX_reg(&rm_ctx); |
| 700 | SS_sig(context) = DX_reg(&rm_ctx); |
| 701 | ESP_sig(context) = EBX_reg(&rm_ctx); |
| 702 | CS_sig(context) = SI_reg(&rm_ctx); |
| 703 | EIP_sig(context) = EDI_reg(&rm_ctx); |
| 704 | EBP_sig(context) = EBP_reg(&rm_ctx); |
| 705 | FS_sig(context) = 0; |
| 706 | GS_sig(context) = 0; |
| 707 | |
| 708 | /* Return to new address and hope that we didn't mess up */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 709 | TRACE("re-entering protected mode at %04x:%08lx\n", |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 710 | CS_sig(context), EIP_sig(context)); |
| 711 | } |
Alexandre Julliard | a1089c5 | 1999-08-01 12:51:55 +0000 | [diff] [blame] | 712 | #endif |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 713 | |
| 714 | #else |
Alexandre Julliard | a1089c5 | 1999-08-01 12:51:55 +0000 | [diff] [blame] | 715 | #if 0 |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 716 | void WINAPI DPMI_RawModeSwitch( SIGCONTEXT *context ) |
| 717 | { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 718 | ERR("don't even think about DPMI raw mode switch without DOS support!\n"); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 719 | ExitProcess(1); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 720 | } |
| 721 | #endif |
Alexandre Julliard | a1089c5 | 1999-08-01 12:51:55 +0000 | [diff] [blame] | 722 | #endif |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 723 | |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 724 | #define DOS_APP_ISDOS(addr,base) ((addr) < 0x110000) |
| 725 | #define DOS_WINE_ISDOS(addr,base) (((addr) >= (base)) && ((addr) < (base) + 0x110000)) |
| 726 | #define DOS_UC_APPTOWINE(addr,base) ((addr) + (base)) |
| 727 | #define DOS_UC_WINETOAPP(addr,base) ((addr) - (base)) |
| 728 | #define DOS_APPTOWINE(addr,base) (DOS_APP_ISDOS(addr,base) ? DOS_UC_APPTOWINE(addr,base) : (addr)) |
| 729 | #define DOS_WINETOAPP(addr,base) (DOS_WINE_ISDOS(addr,base) ? DOS_UC_WINETOAPP(addr,base) : (addr)) |
| 730 | #define DOS_BADLIMIT(addr,base,limit) \ |
| 731 | ((limit == 0xffffffff) || /* disallow "fat DS" for now */ \ |
| 732 | (DOS_WINE_ISDOS(addr,base) && \ |
| 733 | ((addr) + (limit) > (base) + 0x110000))) |
| 734 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 735 | /********************************************************************** |
Alexandre Julliard | e2991ea | 1995-07-29 13:09:43 +0000 | [diff] [blame] | 736 | * INT_Int31Handler |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 737 | * |
Alexandre Julliard | e2991ea | 1995-07-29 13:09:43 +0000 | [diff] [blame] | 738 | * Handler for int 31h (DPMI). |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 739 | */ |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 740 | |
Alexandre Julliard | 617955d | 1999-06-26 18:40:24 +0000 | [diff] [blame] | 741 | void WINAPI INT_Int31Handler( CONTEXT86 *context ) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 742 | { |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 743 | /* |
| 744 | * Note: For Win32s processes, the whole linear address space is |
| 745 | * shifted by 0x10000 relative to the OS linear address space. |
| 746 | * See the comment in msdos/vxd.c. |
| 747 | */ |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 748 | DWORD offset = W32S_APPLICATION() ? W32S_OFFSET : 0; |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 749 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 750 | DWORD dw; |
| 751 | BYTE *ptr; |
| 752 | |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 753 | LPDOSTASK lpDosTask = MZ_Current(); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 754 | |
| 755 | #ifdef MZ_SUPPORTED |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 756 | if (ISV86(context) && lpDosTask) { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 757 | /* Called from real mode, check if it's our wrapper */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 758 | TRACE("called from real mode\n"); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 759 | if (CS_reg(context)==lpDosTask->dpmi_seg) { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 760 | /* This is the protected mode switch */ |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 761 | StartPM(context,lpDosTask); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 762 | return; |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 763 | } else |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 764 | if (CS_reg(context)==lpDosTask->xms_seg) { |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 765 | /* This is the XMS driver entry point */ |
| 766 | XMS_Handler(context); |
| 767 | return; |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 768 | } else |
| 769 | { |
| 770 | /* Check for RMCB */ |
| 771 | RMCB *CurrRMCB = FirstRMCB; |
| 772 | |
| 773 | while (CurrRMCB && (HIWORD(CurrRMCB->address) != CS_reg(context))) |
| 774 | CurrRMCB = CurrRMCB->next; |
| 775 | |
| 776 | if (CurrRMCB) { |
| 777 | /* RMCB call, propagate to protected-mode handler */ |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 778 | DPMI_CallRMCBProc(context, CurrRMCB, lpDosTask->dpmi_flag); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 779 | return; |
| 780 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 781 | } |
| 782 | } |
| 783 | #endif |
| 784 | |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 785 | RESET_CFLAG(context); |
| 786 | switch(AX_reg(context)) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 787 | { |
| 788 | case 0x0000: /* Allocate LDT descriptors */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 789 | TRACE("allocate LDT descriptors (%d)\n",CX_reg(context)); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 790 | if (!(EAX_reg(context) = AllocSelectorArray16( CX_reg(context) ))) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 791 | { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 792 | TRACE("failed\n"); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 793 | EAX_reg(context) = 0x8011; /* descriptor unavailable */ |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 794 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 795 | } |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 796 | TRACE("success, array starts at 0x%04x\n",AX_reg(context)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 797 | break; |
| 798 | |
| 799 | case 0x0001: /* Free LDT descriptor */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 800 | TRACE("free LDT descriptor (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 801 | if (FreeSelector16( BX_reg(context) )) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 802 | { |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 803 | EAX_reg(context) = 0x8022; /* invalid selector */ |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 804 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 805 | } |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 806 | else |
| 807 | { |
| 808 | /* If a segment register contains the selector being freed, */ |
| 809 | /* set it to zero. */ |
| 810 | if (!((DS_reg(context)^BX_reg(context)) & ~3)) DS_reg(context) = 0; |
| 811 | if (!((ES_reg(context)^BX_reg(context)) & ~3)) ES_reg(context) = 0; |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 812 | if (!((FS_reg(context)^BX_reg(context)) & ~3)) FS_reg(context) = 0; |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 813 | if (!((GS_reg(context)^BX_reg(context)) & ~3)) GS_reg(context) = 0; |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 814 | } |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 815 | break; |
| 816 | |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 817 | case 0x0002: /* Real mode segment to descriptor */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 818 | TRACE("real mode segment to descriptor (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 819 | { |
| 820 | WORD entryPoint = 0; /* KERNEL entry point for descriptor */ |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 821 | switch(BX_reg(context)) |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 822 | { |
| 823 | case 0x0000: entryPoint = 183; break; /* __0000H */ |
| 824 | case 0x0040: entryPoint = 193; break; /* __0040H */ |
| 825 | case 0xa000: entryPoint = 174; break; /* __A000H */ |
| 826 | case 0xb000: entryPoint = 181; break; /* __B000H */ |
| 827 | case 0xb800: entryPoint = 182; break; /* __B800H */ |
| 828 | case 0xc000: entryPoint = 195; break; /* __C000H */ |
| 829 | case 0xd000: entryPoint = 179; break; /* __D000H */ |
| 830 | case 0xe000: entryPoint = 190; break; /* __E000H */ |
| 831 | case 0xf000: entryPoint = 194; break; /* __F000H */ |
| 832 | default: |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 833 | EAX_reg(context) = DOSMEM_AllocSelector(BX_reg(context)); |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 834 | break; |
| 835 | } |
| 836 | if (entryPoint) |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 837 | EAX_reg(context) = LOWORD(NE_GetEntryPoint( GetModuleHandle16( "KERNEL" ), |
| 838 | entryPoint )); |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 839 | } |
| 840 | break; |
| 841 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 842 | case 0x0003: /* Get next selector increment */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 843 | TRACE("get selector increment (__AHINCR)\n"); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 844 | EAX_reg(context) = __AHINCR; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 845 | break; |
| 846 | |
| 847 | case 0x0004: /* Lock selector (not supported) */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 848 | FIXME("lock selector not supported\n"); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 849 | EAX_reg(context) = 0; /* FIXME: is this a correct return value? */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 850 | break; |
| 851 | |
| 852 | case 0x0005: /* Unlock selector (not supported) */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 853 | FIXME("unlock selector not supported\n"); |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 854 | EAX_reg(context) = 0; /* FIXME: is this a correct return value? */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 855 | break; |
| 856 | |
| 857 | case 0x0006: /* Get selector base address */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 858 | TRACE("get selector base address (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 859 | if (!(dw = GetSelectorBase( BX_reg(context) ))) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 860 | { |
Alexandre Julliard | 7d8cfeb | 1999-08-01 14:58:01 +0000 | [diff] [blame] | 861 | EAX_reg(context) = 0x8022; /* invalid selector */ |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 862 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 863 | } |
| 864 | else |
| 865 | { |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 866 | #ifdef MZ_SUPPORTED |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 867 | if (lpDosTask) { |
| 868 | DWORD base = (DWORD)DOSMEM_MemoryBase(lpDosTask->hModule); |
| 869 | dw = DOS_WINETOAPP(dw, base); |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 870 | } |
| 871 | #endif |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 872 | CX_reg(context) = HIWORD(W32S_WINE2APP(dw, offset)); |
| 873 | DX_reg(context) = LOWORD(W32S_WINE2APP(dw, offset)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 874 | } |
| 875 | break; |
| 876 | |
| 877 | case 0x0007: /* Set selector base address */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 878 | TRACE("set selector base address (0x%04x,0x%08lx)\n", |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 879 | BX_reg(context), |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 880 | W32S_APP2WINE(MAKELONG(DX_reg(context),CX_reg(context)), offset)); |
| 881 | dw = W32S_APP2WINE(MAKELONG(DX_reg(context), CX_reg(context)), offset); |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 882 | #ifdef MZ_SUPPORTED |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 883 | if (lpDosTask) { |
| 884 | DWORD base = (DWORD)DOSMEM_MemoryBase(lpDosTask->hModule); |
| 885 | dw = DOS_APPTOWINE(dw, base); |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 886 | } |
| 887 | #endif |
| 888 | SetSelectorBase(BX_reg(context), dw); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 889 | break; |
| 890 | |
| 891 | case 0x0008: /* Set selector limit */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 892 | TRACE("set selector limit (0x%04x,0x%08lx)\n",BX_reg(context),MAKELONG(DX_reg(context),CX_reg(context))); |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 893 | dw = MAKELONG( DX_reg(context), CX_reg(context) ); |
| 894 | #ifdef MZ_SUPPORTED |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 895 | if (lpDosTask) { |
| 896 | DWORD base = (DWORD)DOSMEM_MemoryBase(lpDosTask->hModule); |
| 897 | DWORD sbase = GetSelectorBase( BX_reg(context) ); |
| 898 | if (!sbase) { |
| 899 | /* the app has set the limit without setting the base, |
| 900 | * it must be relying on that the default should be DOS space; |
| 901 | * so set the base address now */ |
| 902 | SetSelectorBase( BX_reg(context), sbase = base ); |
| 903 | if (dw == 0xffffffff) { |
| 904 | /* djgpp does this without checking (in _dos_ds setup, crt1.c), |
| 905 | * so we have to override the limit here */ |
| 906 | dw = 0x110000; |
| 907 | } |
| 908 | } |
| 909 | if (DOS_BADLIMIT(sbase, base, dw)) { |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 910 | AX_reg(context) = 0x8021; /* invalid value */ |
| 911 | SET_CFLAG(context); |
| 912 | break; |
| 913 | } |
| 914 | } |
| 915 | #endif |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 916 | SetSelectorLimit16( BX_reg(context), dw ); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 917 | break; |
| 918 | |
| 919 | case 0x0009: /* Set selector access rights */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 920 | TRACE("set selector access rights(0x%04x,0x%04x)\n",BX_reg(context),CX_reg(context)); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 921 | SelectorAccessRights16( BX_reg(context), 1, CX_reg(context) ); |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 922 | break; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 923 | |
| 924 | case 0x000a: /* Allocate selector alias */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 925 | TRACE("allocate selector alias (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 926 | if (!(AX_reg(context) = AllocCStoDSAlias16( BX_reg(context) ))) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 927 | { |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 928 | AX_reg(context) = 0x8011; /* descriptor unavailable */ |
| 929 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 930 | } |
| 931 | break; |
| 932 | |
| 933 | case 0x000b: /* Get descriptor */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 934 | TRACE("get descriptor (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 935 | { |
| 936 | ldt_entry entry; |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 937 | LDT_GetEntry( SELECTOR_TO_ENTRY( BX_reg(context) ), &entry ); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 938 | #ifdef MZ_SUPPORTED |
| 939 | if (lpDosTask) { |
| 940 | DWORD base = (DWORD)DOSMEM_MemoryBase(lpDosTask->hModule); |
| 941 | entry.base = DOS_WINETOAPP(entry.base, base); |
| 942 | } |
| 943 | #endif |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 944 | entry.base = W32S_WINE2APP(entry.base, offset); |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 945 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 946 | /* FIXME: should use ES:EDI for 32-bit clients */ |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 947 | LDT_EntryToBytes( PTR_SEG_OFF_TO_LIN( ES_reg(context), |
| 948 | DI_reg(context) ), &entry ); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 949 | } |
| 950 | break; |
| 951 | |
| 952 | case 0x000c: /* Set descriptor */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 953 | TRACE("set descriptor (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 954 | { |
| 955 | ldt_entry entry; |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 956 | LDT_BytesToEntry( PTR_SEG_OFF_TO_LIN( ES_reg(context), |
| 957 | DI_reg(context) ), &entry ); |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 958 | entry.base = W32S_APP2WINE(entry.base, offset); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 959 | #ifdef MZ_SUPPORTED |
| 960 | if (lpDosTask) { |
| 961 | DWORD base = (DWORD)DOSMEM_MemoryBase(lpDosTask->hModule); |
| 962 | entry.base = DOS_APPTOWINE(entry.base, base); |
| 963 | if (DOS_BADLIMIT(entry.base, base, entry.limit)) { |
| 964 | AX_reg(context) = 0x8021; /* invalid value */ |
| 965 | SET_CFLAG(context); |
| 966 | break; |
| 967 | } |
| 968 | } |
| 969 | #endif |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 970 | |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 971 | LDT_SetEntry( SELECTOR_TO_ENTRY( BX_reg(context) ), &entry ); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 972 | } |
| 973 | break; |
| 974 | |
| 975 | case 0x000d: /* Allocate specific LDT descriptor */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 976 | FIXME("allocate descriptor (0x%04x), stub!\n",BX_reg(context)); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 977 | AX_reg(context) = 0x8011; /* descriptor unavailable */ |
| 978 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 979 | break; |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 980 | case 0x0100: /* Allocate DOS memory block */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 981 | TRACE("allocate DOS memory block (0x%x paragraphs)\n",BX_reg(context)); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 982 | dw = GlobalDOSAlloc16((DWORD)BX_reg(context)<<4); |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 983 | if (dw) { |
| 984 | AX_reg(context) = HIWORD(dw); |
| 985 | DX_reg(context) = LOWORD(dw); |
| 986 | } else { |
| 987 | AX_reg(context) = 0x0008; /* insufficient memory */ |
| 988 | BX_reg(context) = DOSMEM_Available(0)>>4; |
| 989 | SET_CFLAG(context); |
| 990 | } |
| 991 | break; |
| 992 | case 0x0101: /* Free DOS memory block */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 993 | TRACE("free DOS memory block (0x%04x)\n",DX_reg(context)); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 994 | dw = GlobalDOSFree16(DX_reg(context)); |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 995 | if (!dw) { |
| 996 | AX_reg(context) = 0x0009; /* memory block address invalid */ |
| 997 | SET_CFLAG(context); |
| 998 | } |
| 999 | break; |
Alexandre Julliard | 2c69f6d | 1996-09-28 18:11:01 +0000 | [diff] [blame] | 1000 | case 0x0200: /* get real mode interrupt vector */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1001 | FIXME("get realmode interupt vector(0x%02x) unimplemented.\n", |
Alexandre Julliard | 54c2711 | 1998-03-29 19:44:57 +0000 | [diff] [blame] | 1002 | BL_reg(context)); |
Alexandre Julliard | 2c69f6d | 1996-09-28 18:11:01 +0000 | [diff] [blame] | 1003 | SET_CFLAG(context); |
| 1004 | break; |
| 1005 | case 0x0201: /* set real mode interrupt vector */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1006 | FIXME("set realmode interupt vector(0x%02x,0x%04x:0x%04x) unimplemented\n", BL_reg(context),CX_reg(context),DX_reg(context)); |
Alexandre Julliard | 2c69f6d | 1996-09-28 18:11:01 +0000 | [diff] [blame] | 1007 | SET_CFLAG(context); |
| 1008 | break; |
Alexandre Julliard | e2991ea | 1995-07-29 13:09:43 +0000 | [diff] [blame] | 1009 | case 0x0204: /* Get protected mode interrupt vector */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1010 | TRACE("get protected mode interrupt handler (0x%02x), stub!\n",BL_reg(context)); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1011 | dw = (DWORD)INT_GetPMHandler( BL_reg(context) ); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1012 | CX_reg(context) = HIWORD(dw); |
| 1013 | DX_reg(context) = LOWORD(dw); |
Alexandre Julliard | e2991ea | 1995-07-29 13:09:43 +0000 | [diff] [blame] | 1014 | break; |
| 1015 | |
| 1016 | case 0x0205: /* Set protected mode interrupt vector */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1017 | TRACE("set protected mode interrupt handler (0x%02x,%p), stub!\n", |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 1018 | BL_reg(context),PTR_SEG_OFF_TO_LIN(CX_reg(context),DX_reg(context))); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1019 | INT_SetPMHandler( BL_reg(context), |
| 1020 | (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( CX_reg(context), |
| 1021 | DX_reg(context) )); |
Alexandre Julliard | e2991ea | 1995-07-29 13:09:43 +0000 | [diff] [blame] | 1022 | break; |
| 1023 | |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 1024 | case 0x0300: /* Simulate real mode interrupt */ |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 1025 | CallRMInt( context ); |
Alexandre Julliard | d7d4fdf | 1995-12-26 15:05:24 +0000 | [diff] [blame] | 1026 | break; |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 1027 | |
Alexandre Julliard | d7d4fdf | 1995-12-26 15:05:24 +0000 | [diff] [blame] | 1028 | case 0x0301: /* Call real mode procedure with far return */ |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 1029 | CallRMProc( context, FALSE ); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 1030 | break; |
Alexandre Julliard | d7d4fdf | 1995-12-26 15:05:24 +0000 | [diff] [blame] | 1031 | |
| 1032 | case 0x0302: /* Call real mode procedure with interrupt return */ |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame] | 1033 | CallRMProc( context, TRUE ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 1034 | break; |
| 1035 | |
Alexandre Julliard | ac9c9b0 | 1996-07-28 18:50:11 +0000 | [diff] [blame] | 1036 | case 0x0303: /* Allocate Real Mode Callback Address */ |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 1037 | AllocRMCB( context ); |
| 1038 | break; |
Alexandre Julliard | ac9c9b0 | 1996-07-28 18:50:11 +0000 | [diff] [blame] | 1039 | |
Alexandre Julliard | 60ce85c | 1998-02-01 18:33:27 +0000 | [diff] [blame] | 1040 | case 0x0304: /* Free Real Mode Callback Address */ |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 1041 | FreeRMCB( context ); |
Alexandre Julliard | 60ce85c | 1998-02-01 18:33:27 +0000 | [diff] [blame] | 1042 | break; |
| 1043 | |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 1044 | case 0x0305: /* Get State Save/Restore Addresses */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1045 | TRACE("get state save/restore addresses\n"); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 1046 | /* we probably won't need this kind of state saving */ |
| 1047 | AX_reg(context) = 0; |
| 1048 | /* real mode: just point to the lret */ |
| 1049 | BX_reg(context) = DPMI_wrap_seg; |
| 1050 | ECX_reg(context) = 2; |
| 1051 | /* protected mode: don't have any handler yet... */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1052 | FIXME("no protected-mode dummy state save/restore handler yet\n"); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 1053 | SI_reg(context) = 0; |
| 1054 | EDI_reg(context) = 0; |
| 1055 | break; |
| 1056 | |
| 1057 | case 0x0306: /* Get Raw Mode Switch Addresses */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1058 | TRACE("get raw mode switch addresses\n"); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 1059 | if (lpDosTask) { |
| 1060 | /* real mode, point to standard DPMI return wrapper */ |
| 1061 | BX_reg(context) = DPMI_wrap_seg; |
| 1062 | ECX_reg(context) = 0; |
| 1063 | /* protected mode, point to DPMI call wrapper */ |
| 1064 | SI_reg(context) = lpDosTask->dpmi_sel; |
| 1065 | EDI_reg(context) = 8; /* offset of the INT 0x31 call */ |
| 1066 | } else { |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1067 | ERR("win app attempting to get raw mode switch!\n"); |
Ove Kaaven | e78e1af | 1999-06-12 08:09:52 +0000 | [diff] [blame] | 1068 | AX_reg(context) = 0x8001; /* unsupported function */ |
| 1069 | SET_CFLAG(context); |
| 1070 | } |
| 1071 | break; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1072 | case 0x0400: /* Get DPMI version */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1073 | TRACE("get DPMI version\n"); |
Alexandre Julliard | 349a953 | 1997-02-02 19:01:52 +0000 | [diff] [blame] | 1074 | { |
| 1075 | SYSTEM_INFO si; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1076 | |
Alexandre Julliard | 349a953 | 1997-02-02 19:01:52 +0000 | [diff] [blame] | 1077 | GetSystemInfo(&si); |
| 1078 | AX_reg(context) = 0x005a; /* DPMI version 0.90 */ |
| 1079 | BX_reg(context) = 0x0005; /* Flags: 32-bit, virtual memory */ |
| 1080 | CL_reg(context) = si.wProcessorLevel; |
| 1081 | DX_reg(context) = 0x0102; /* Master/slave interrupt controller base*/ |
| 1082 | break; |
| 1083 | } |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1084 | case 0x0500: /* Get free memory information */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1085 | TRACE("get free memory information\n"); |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 1086 | { |
| 1087 | MEMMANINFO mmi; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1088 | |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 1089 | mmi.dwSize = sizeof(mmi); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1090 | MemManInfo16(&mmi); |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 1091 | ptr = (BYTE *)PTR_SEG_OFF_TO_LIN(ES_reg(context),DI_reg(context)); |
| 1092 | /* the layout is just the same as MEMMANINFO, but without |
| 1093 | * the dwSize entry. |
| 1094 | */ |
| 1095 | memcpy(ptr,((char*)&mmi)+4,sizeof(mmi)-4); |
| 1096 | break; |
| 1097 | } |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1098 | case 0x0501: /* Allocate memory block */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1099 | TRACE("allocate memory block (%ld)\n",MAKELONG(CX_reg(context),BX_reg(context))); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 1100 | if (!(ptr = (BYTE *)DPMI_xalloc(MAKELONG(CX_reg(context), BX_reg(context))))) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1101 | { |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1102 | AX_reg(context) = 0x8012; /* linear memory not available */ |
| 1103 | SET_CFLAG(context); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 1104 | } else { |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 1105 | BX_reg(context) = SI_reg(context) = HIWORD(W32S_WINE2APP(ptr, offset)); |
| 1106 | CX_reg(context) = DI_reg(context) = LOWORD(W32S_WINE2APP(ptr, offset)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1107 | } |
| 1108 | break; |
| 1109 | |
| 1110 | case 0x0502: /* Free memory block */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1111 | TRACE("free memory block (0x%08lx)\n", |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 1112 | W32S_APP2WINE(MAKELONG(DI_reg(context),SI_reg(context)), offset)); |
| 1113 | DPMI_xfree( (void *)W32S_APP2WINE(MAKELONG(DI_reg(context), |
| 1114 | SI_reg(context)), offset) ); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1115 | break; |
| 1116 | |
| 1117 | case 0x0503: /* Resize memory block */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1118 | TRACE("resize memory block (0x%08lx,%ld)\n", |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 1119 | W32S_APP2WINE(MAKELONG(DI_reg(context),SI_reg(context)), offset), |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 1120 | MAKELONG(CX_reg(context),BX_reg(context))); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 1121 | if (!(ptr = (BYTE *)DPMI_xrealloc( |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 1122 | (void *)W32S_APP2WINE(MAKELONG(DI_reg(context),SI_reg(context)), offset), |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 1123 | MAKELONG(CX_reg(context),BX_reg(context))))) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1124 | { |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1125 | AX_reg(context) = 0x8012; /* linear memory not available */ |
| 1126 | SET_CFLAG(context); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 1127 | } else { |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 1128 | BX_reg(context) = SI_reg(context) = HIWORD(W32S_WINE2APP(ptr, offset)); |
| 1129 | CX_reg(context) = DI_reg(context) = LOWORD(W32S_WINE2APP(ptr, offset)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1130 | } |
| 1131 | break; |
| 1132 | |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 1133 | case 0x0507: /* Modify page attributes */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1134 | FIXME("modify page attributes unimplemented\n"); |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 1135 | break; /* Just ignore it */ |
| 1136 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1137 | case 0x0600: /* Lock linear region */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1138 | FIXME("lock linear region unimplemented\n"); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1139 | break; /* Just ignore it */ |
| 1140 | |
| 1141 | case 0x0601: /* Unlock linear region */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1142 | FIXME("unlock linear region unimplemented\n"); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1143 | break; /* Just ignore it */ |
| 1144 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 1145 | case 0x0602: /* Unlock real-mode region */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1146 | FIXME("unlock realmode region unimplemented\n"); |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 1147 | break; /* Just ignore it */ |
| 1148 | |
| 1149 | case 0x0603: /* Lock real-mode region */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1150 | FIXME("lock realmode region unimplemented\n"); |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 1151 | break; /* Just ignore it */ |
| 1152 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1153 | case 0x0604: /* Get page size */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1154 | TRACE("get pagesize\n"); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1155 | BX_reg(context) = 0; |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 1156 | CX_reg(context) = VIRTUAL_GetPageSize(); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1157 | break; |
| 1158 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 1159 | case 0x0702: /* Mark page as demand-paging candidate */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1160 | FIXME("mark page as demand-paging candidate\n"); |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 1161 | break; /* Just ignore it */ |
| 1162 | |
| 1163 | case 0x0703: /* Discard page contents */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1164 | FIXME("discard page contents\n"); |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 1165 | break; /* Just ignore it */ |
| 1166 | |
Alexandre Julliard | 03468f7 | 1998-02-15 19:40:49 +0000 | [diff] [blame] | 1167 | case 0x0800: /* Physical address mapping */ |
Alexandre Julliard | 61fece0 | 1999-06-26 19:09:08 +0000 | [diff] [blame] | 1168 | FIXME("map real to linear (0x%08lx)\n",MAKELONG(CX_reg(context),BX_reg(context))); |
Alexandre Julliard | 03468f7 | 1998-02-15 19:40:49 +0000 | [diff] [blame] | 1169 | if(!(ptr=DOSMEM_MapRealToLinear(MAKELONG(CX_reg(context),BX_reg(context))))) |
| 1170 | { |
| 1171 | AX_reg(context) = 0x8021; |
| 1172 | SET_CFLAG(context); |
| 1173 | } |
| 1174 | else |
| 1175 | { |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 1176 | BX_reg(context) = HIWORD(W32S_WINE2APP(ptr, offset)); |
| 1177 | CX_reg(context) = LOWORD(W32S_WINE2APP(ptr, offset)); |
Alexandre Julliard | 03468f7 | 1998-02-15 19:40:49 +0000 | [diff] [blame] | 1178 | RESET_CFLAG(context); |
| 1179 | } |
| 1180 | break; |
| 1181 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1182 | default: |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1183 | INT_BARF( context, 0x31 ); |
| 1184 | AX_reg(context) = 0x8001; /* unsupported function */ |
| 1185 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1186 | break; |
| 1187 | } |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 1188 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1189 | } |