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> |
| 9 | #include "windows.h" |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 10 | #include "heap.h" |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 11 | #include "global.h" |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 12 | #include "ldt.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 "drive.h" |
| 16 | #include "msdos.h" |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 17 | #include "task.h" |
| 18 | #include "dosexe.h" |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 19 | #include "toolhelp.h" |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 20 | #include "debug.h" |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 21 | #include "selectors.h" |
| 22 | #include "thread.h" |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 23 | #include "process.h" |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 24 | #include "stackframe.h" |
| 25 | #include "callback.h" |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +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 | |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 66 | /********************************************************************** |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 67 | * DPMI_xalloc |
| 68 | * special virtualalloc, allocates lineary monoton growing memory. |
| 69 | * (the usual VirtualAlloc does not satisfy that restriction) |
| 70 | */ |
| 71 | static LPVOID |
| 72 | DPMI_xalloc(int len) { |
| 73 | LPVOID ret; |
| 74 | LPVOID oldlastv = lastvalloced; |
| 75 | |
| 76 | if (lastvalloced) { |
| 77 | int xflag = 0; |
| 78 | ret = NULL; |
| 79 | while (!ret) { |
| 80 | ret=VirtualAlloc(lastvalloced,len,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE); |
| 81 | if (!ret) |
| 82 | lastvalloced+=0x10000; |
| 83 | /* we failed to allocate one in the first round. |
| 84 | * try non-linear |
| 85 | */ |
| 86 | if (!xflag && (lastvalloced<oldlastv)) { /* wrapped */ |
| 87 | FIXME(int31,"failed to allocate lineary growing memory (%d bytes), using non-linear growing...\n",len); |
| 88 | xflag++; |
| 89 | } |
| 90 | /* if we even fail to allocate something in the next |
| 91 | * round, return NULL |
| 92 | */ |
| 93 | if ((xflag==1) && (lastvalloced >= oldlastv)) |
| 94 | xflag++; |
| 95 | if ((xflag==2) && (lastvalloced < oldlastv)) { |
| 96 | FIXME(int31,"failed to allocate any memory of %d bytes!\n",len); |
| 97 | return NULL; |
| 98 | } |
| 99 | } |
| 100 | } else |
| 101 | ret=VirtualAlloc(NULL,len,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE); |
| 102 | lastvalloced = (LPVOID)(((DWORD)ret+len+0xffff)&~0xffff); |
| 103 | return ret; |
| 104 | } |
| 105 | |
| 106 | static void |
| 107 | DPMI_xfree(LPVOID ptr) { |
| 108 | VirtualFree(ptr,0,MEM_RELEASE); |
| 109 | } |
| 110 | |
| 111 | /* FIXME: perhaps we could grow this mapped area... */ |
| 112 | static LPVOID |
| 113 | DPMI_xrealloc(LPVOID ptr,int newsize) { |
| 114 | MEMORY_BASIC_INFORMATION mbi; |
| 115 | LPVOID newptr; |
| 116 | |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 117 | newptr = DPMI_xalloc(newsize); |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 118 | if (ptr) { |
| 119 | if (!VirtualQuery(ptr,&mbi,sizeof(mbi))) { |
| 120 | FIXME(int31,"realloc of DPMI_xallocd region %p?\n",ptr); |
| 121 | return NULL; |
| 122 | } |
| 123 | if (mbi.State == MEM_FREE) { |
| 124 | FIXME(int31,"realloc of DPMI_xallocd region %p?\n",ptr); |
| 125 | return NULL; |
| 126 | } |
| 127 | /* We do not shrink allocated memory. most reallocs |
| 128 | * only do grows anyway |
| 129 | */ |
| 130 | if (newsize<=mbi.RegionSize) |
| 131 | return ptr; |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 132 | memcpy(newptr,ptr,mbi.RegionSize); |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 133 | DPMI_xfree(ptr); |
| 134 | } |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 135 | return newptr; |
| 136 | } |
| 137 | /********************************************************************** |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 138 | * INT_GetRealModeContext |
| 139 | */ |
| 140 | static void INT_GetRealModeContext( REALMODECALL *call, CONTEXT *context ) |
| 141 | { |
| 142 | EAX_reg(context) = call->eax; |
| 143 | EBX_reg(context) = call->ebx; |
| 144 | ECX_reg(context) = call->ecx; |
| 145 | EDX_reg(context) = call->edx; |
| 146 | ESI_reg(context) = call->esi; |
| 147 | EDI_reg(context) = call->edi; |
| 148 | EBP_reg(context) = call->ebp; |
Ove Kaaven | 99c174e | 1998-11-01 12:53:17 +0000 | [diff] [blame] | 149 | EFL_reg(context) = call->fl | V86_FLAG; |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 150 | EIP_reg(context) = call->ip; |
| 151 | ESP_reg(context) = call->sp; |
| 152 | CS_reg(context) = call->cs; |
| 153 | DS_reg(context) = call->ds; |
| 154 | ES_reg(context) = call->es; |
| 155 | FS_reg(context) = call->fs; |
| 156 | GS_reg(context) = call->gs; |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 157 | (char*)V86BASE(context) = DOSMEM_MemoryBase(0); |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | |
| 161 | /********************************************************************** |
| 162 | * INT_SetRealModeContext |
| 163 | */ |
| 164 | static void INT_SetRealModeContext( REALMODECALL *call, CONTEXT *context ) |
| 165 | { |
| 166 | call->eax = EAX_reg(context); |
| 167 | call->ebx = EBX_reg(context); |
| 168 | call->ecx = ECX_reg(context); |
| 169 | call->edx = EDX_reg(context); |
| 170 | call->esi = ESI_reg(context); |
| 171 | call->edi = EDI_reg(context); |
| 172 | call->ebp = EBP_reg(context); |
| 173 | call->fl = FL_reg(context); |
| 174 | call->ip = IP_reg(context); |
| 175 | call->sp = SP_reg(context); |
| 176 | call->cs = CS_reg(context); |
| 177 | call->ds = DS_reg(context); |
| 178 | call->es = ES_reg(context); |
| 179 | call->fs = FS_reg(context); |
| 180 | call->gs = GS_reg(context); |
| 181 | } |
| 182 | |
| 183 | |
| 184 | /********************************************************************** |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 185 | * DPMI_CallRMCBProc |
| 186 | * |
| 187 | * This routine does the hard work of calling a callback procedure. |
| 188 | */ |
| 189 | static void DPMI_CallRMCBProc( CONTEXT *context, RMCB *rmcb, WORD flag ) |
| 190 | { |
| 191 | if (IS_SELECTOR_SYSTEM( rmcb->proc_sel )) { |
| 192 | /* Wine-internal RMCB, call directly */ |
| 193 | ((RMCBPROC)rmcb->proc_ofs)(context); |
| 194 | } else { |
| 195 | #ifdef __i386__ |
| 196 | UINT16 ss,es; |
| 197 | DWORD edi; |
| 198 | |
| 199 | INT_SetRealModeContext((REALMODECALL *)PTR_SEG_OFF_TO_LIN( rmcb->regs_sel, rmcb->regs_ofs ), context); |
| 200 | ss = SELECTOR_AllocBlock( DOSMEM_MemoryBase(0) + (DWORD)(SS_reg(context)<<4), 0x10000, SEGMENT_DATA, FALSE, FALSE ); |
| 201 | |
| 202 | FIXME(int31,"untested!\n"); |
| 203 | |
| 204 | /* The called proc ends with an IRET, and takes these parameters: |
| 205 | * DS:ESI = pointer to real-mode SS:SP |
| 206 | * ES:EDI = pointer to real-mode call structure |
| 207 | * It returns: |
| 208 | * ES:EDI = pointer to real-mode call structure (may be a copy) |
| 209 | * It is the proc's responsibility to change the return CS:IP in the |
| 210 | * real-mode call structure. */ |
| 211 | if (flag & 1) { |
| 212 | /* 32-bit DPMI client */ |
| 213 | __asm__ __volatile__(" |
| 214 | pushl %%es |
| 215 | pushl %%ds |
| 216 | pushfl |
| 217 | movl %4,%%es |
| 218 | movl %3,%%ds |
| 219 | lcall %2 |
| 220 | popl %%ds |
| 221 | movl %%es,%0 |
| 222 | popl %%es |
| 223 | " |
| 224 | : "=g" (es), "=D" (edi) |
| 225 | : "m" (rmcb->proc_ofs), |
| 226 | "g" (ss), "g" (rmcb->regs_sel), |
| 227 | "S" (ESP_reg(context)), "D" (rmcb->regs_ofs) |
| 228 | : "eax", "ecx", "edx", "esi", "ebp" ); |
| 229 | } else { |
| 230 | /* 16-bit DPMI client */ |
| 231 | CONTEXT ctx = *context; |
| 232 | CS_reg(&ctx) = rmcb->proc_sel; |
| 233 | EIP_reg(&ctx) = rmcb->proc_ofs; |
| 234 | DS_reg(&ctx) = ss; |
| 235 | ESI_reg(&ctx) = ESP_reg(context); |
| 236 | ES_reg(&ctx) = rmcb->regs_sel; |
| 237 | EDI_reg(&ctx) = rmcb->regs_ofs; |
| 238 | Callbacks->CallRegisterShortProc(&ctx, 2); |
| 239 | es = ES_reg(&ctx); |
| 240 | edi = EDI_reg(&ctx); |
| 241 | } |
| 242 | UnMapLS(PTR_SEG_OFF_TO_SEGPTR(ss,0)); |
| 243 | INT_GetRealModeContext((REALMODECALL*)PTR_SEG_OFF_TO_LIN( es, edi ), context); |
| 244 | #else |
| 245 | ERR(int31,"RMCBs only implemented for i386\n"); |
| 246 | #endif |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | |
| 251 | /********************************************************************** |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 252 | * DPMI_CallRMProc |
| 253 | * |
| 254 | * This routine does the hard work of calling a real mode procedure. |
| 255 | */ |
| 256 | int DPMI_CallRMProc( CONTEXT *context, LPWORD stack, int args, int iret ) |
| 257 | { |
| 258 | LPWORD stack16; |
| 259 | THDB *thdb = THREAD_Current(); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 260 | LPVOID addr = NULL; /* avoid gcc warning */ |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 261 | TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() ); |
| 262 | NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL; |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 263 | RMCB *CurrRMCB; |
| 264 | int alloc = 0, already = 0; |
Patrik Stridvall | c9e1950 | 1998-10-24 11:18:18 +0000 | [diff] [blame] | 265 | WORD sel; |
| 266 | SEGPTR seg_addr; |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 267 | |
| 268 | GlobalUnlock16( GetCurrentTask() ); |
| 269 | |
| 270 | TRACE(int31, "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n", |
| 271 | EAX_reg(context), EBX_reg(context), ECX_reg(context), EDX_reg(context) ); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 272 | TRACE(int31, "ESI=%08lx EDI=%08lx ES=%04x DS=%04x CS:IP=%04x:%04x, %d WORD arguments, %s\n", |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 273 | ESI_reg(context), EDI_reg(context), ES_reg(context), DS_reg(context), |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 274 | CS_reg(context), IP_reg(context), args, iret?"IRET":"FAR" ); |
| 275 | |
| 276 | callrmproc_again: |
| 277 | |
| 278 | /* shortcut for chaining to internal interrupt handlers */ |
| 279 | if ((CS_reg(context) == 0xF000) && iret) { |
| 280 | return INT_RealModeInterrupt( IP_reg(context)/4, context); |
| 281 | } |
| 282 | |
| 283 | /* shortcut for RMCBs */ |
| 284 | CurrRMCB = FirstRMCB; |
| 285 | |
| 286 | while (CurrRMCB && (HIWORD(CurrRMCB->address) != CS_reg(context))) |
| 287 | CurrRMCB = CurrRMCB->next; |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 288 | |
| 289 | #ifdef MZ_SUPPORTED |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 290 | FIXME(int31,"DPMI real-mode call using DOS VM task system, not fully tested!\n"); |
| 291 | if (!(CurrRMCB || pModule->lpDosTask)) { |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 292 | TRACE(int31,"creating VM86 task\n"); |
| 293 | if (MZ_InitTask( MZ_AllocDPMITask( pModule->self ) ) < 32) { |
| 294 | ERR(int31,"could not setup VM86 task\n"); |
| 295 | return 1; |
| 296 | } |
| 297 | } |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 298 | if (!already) { |
| 299 | if (!SS_reg(context)) { |
| 300 | alloc = 1; /* allocate default stack */ |
| 301 | stack16 = addr = DOSMEM_GetBlock( pModule->self, 64, &(SS_reg(context)) ); |
| 302 | SP_reg(context) = 64-2; |
| 303 | stack16 += 32-1; |
| 304 | if (!addr) { |
| 305 | ERR(int31,"could not allocate default stack\n"); |
| 306 | return 1; |
| 307 | } |
| 308 | } else { |
| 309 | stack16 = CTX_SEG_OFF_TO_LIN(context, SS_reg(context), ESP_reg(context)); |
| 310 | } |
| 311 | SP_reg(context) -= (args + (iret?1:0)) * sizeof(WORD); |
| 312 | #else |
| 313 | if (!already) { |
| 314 | stack16 = THREAD_STACK16(thdb); |
| 315 | #endif |
| 316 | stack16 -= args; |
| 317 | if (args) memcpy(stack16, stack, args*sizeof(WORD) ); |
| 318 | /* push flags if iret */ |
| 319 | if (iret) { |
| 320 | stack16--; args++; |
| 321 | *stack16 = FL_reg(context); |
| 322 | } |
| 323 | #ifdef MZ_SUPPORTED |
| 324 | /* push return address (return to interrupt wrapper) */ |
| 325 | *(--stack16) = pModule->lpDosTask->dpmi_seg; |
| 326 | *(--stack16) = pModule->lpDosTask->wrap_ofs; |
| 327 | /* adjust stack */ |
| 328 | SP_reg(context) -= 2*sizeof(WORD); |
| 329 | #endif |
| 330 | already = 1; |
| 331 | } |
| 332 | |
| 333 | if (CurrRMCB) { |
| 334 | /* RMCB call, invoke protected-mode handler directly */ |
| 335 | DPMI_CallRMCBProc(context, CurrRMCB, pModule->lpDosTask?pModule->lpDosTask->dpmi_flag:0); |
| 336 | /* check if we returned to where we thought we would */ |
| 337 | if ((CS_reg(context) != pModule->lpDosTask->dpmi_seg) || |
| 338 | (IP_reg(context) != pModule->lpDosTask->wrap_ofs)) { |
| 339 | /* we need to continue at different address in real-mode space, |
| 340 | so we need to set it all up for real mode again */ |
| 341 | goto callrmproc_again; |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 342 | } |
| 343 | } else { |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 344 | #ifdef MZ_SUPPORTED |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 345 | #if 0 /* this was probably unnecessary */ |
| 346 | /* push call address */ |
| 347 | *(--stack16) = CS_reg(context); |
| 348 | *(--stack16) = IP_reg(context); |
| 349 | /* adjust stack */ |
| 350 | SP_reg(context) -= 2*sizeof(WORD); |
| 351 | /* set initial CS:IP to the wrapper's "lret" */ |
| 352 | CS_reg(context) = pModule->lpDosTask->dpmi_seg; |
| 353 | IP_reg(context) = pModule->lpDosTask->call_ofs; |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 354 | #endif |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 355 | TRACE(int31,"entering real mode...\n"); |
| 356 | DOSVM_Enter( context ); |
| 357 | TRACE(int31,"returned from real-mode call\n"); |
| 358 | #else |
| 359 | addr = CTX_SEG_OFF_TO_LIN(context, CS_reg(context), EIP_reg(context)); |
| 360 | sel = SELECTOR_AllocBlock( addr, 0x10000, SEGMENT_CODE, FALSE, FALSE ); |
| 361 | seg_addr = PTR_SEG_OFF_TO_SEGPTR( sel, 0 ); |
| 362 | |
| 363 | CS_reg(context) = HIWORD(seg_addr); |
| 364 | IP_reg(context) = LOWORD(seg_addr); |
| 365 | EBP_reg(context) = OFFSETOF( thdb->cur_stack ) |
| 366 | + (WORD)&((STACK16FRAME*)0)->bp; |
| 367 | Callbacks->CallRegisterShortProc(context, args*sizeof(WORD)); |
| 368 | UnMapLS(seg_addr); |
| 369 | #endif |
| 370 | } |
| 371 | if (alloc) DOSMEM_FreeBlock( pModule->self, addr ); |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 372 | return 0; |
| 373 | } |
| 374 | |
| 375 | |
| 376 | /********************************************************************** |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 377 | * CallRMInt |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 378 | */ |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 379 | static void CallRMInt( CONTEXT *context ) |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 380 | { |
| 381 | CONTEXT realmode_ctx; |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 382 | FARPROC16 rm_int = INT_GetRMHandler( BL_reg(context) ); |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 383 | REALMODECALL *call = (REALMODECALL *)PTR_SEG_OFF_TO_LIN( ES_reg(context), |
| 384 | DI_reg(context) ); |
| 385 | INT_GetRealModeContext( call, &realmode_ctx ); |
| 386 | |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 387 | /* we need to check if a real-mode program has hooked the interrupt */ |
| 388 | if (HIWORD(rm_int)!=0xF000) { |
| 389 | /* yup, which means we need to switch to real mode... */ |
| 390 | CS_reg(&realmode_ctx) = HIWORD(rm_int); |
| 391 | EIP_reg(&realmode_ctx) = LOWORD(rm_int); |
| 392 | if (DPMI_CallRMProc( &realmode_ctx, NULL, 0, TRUE)) |
| 393 | SET_CFLAG(context); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 394 | } else { |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 395 | RESET_CFLAG(context); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 396 | /* use the IP we have instead of BL_reg, in case some apps |
| 397 | decide to move interrupts around for whatever reason... */ |
| 398 | if (INT_RealModeInterrupt( LOWORD(rm_int)/4, &realmode_ctx )) |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 399 | SET_CFLAG(context); |
| 400 | if (EFL_reg(context)&1) { |
| 401 | FIXME(int31,"%02x: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n", |
| 402 | BL_reg(context), EAX_reg(&realmode_ctx), EBX_reg(&realmode_ctx), |
| 403 | ECX_reg(&realmode_ctx), EDX_reg(&realmode_ctx)); |
| 404 | FIXME(int31," ESI=%08lx EDI=%08lx DS=%04lx ES=%04lx\n", |
| 405 | ESI_reg(&realmode_ctx), EDI_reg(&realmode_ctx), |
| 406 | DS_reg(&realmode_ctx), ES_reg(&realmode_ctx) ); |
| 407 | } |
Alexandre Julliard | dadf78f | 1998-05-17 17:13:43 +0000 | [diff] [blame] | 408 | } |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 409 | INT_SetRealModeContext( call, &realmode_ctx ); |
| 410 | } |
| 411 | |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 412 | |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 413 | static void CallRMProc( CONTEXT *context, int iret ) |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 414 | { |
| 415 | REALMODECALL *p = (REALMODECALL *)PTR_SEG_OFF_TO_LIN( ES_reg(context), DI_reg(context) ); |
| 416 | CONTEXT context16; |
| 417 | THDB *thdb = THREAD_Current(); |
| 418 | WORD argsize, sel; |
| 419 | LPVOID addr; |
| 420 | SEGPTR seg_addr; |
| 421 | |
| 422 | TRACE(int31, "RealModeCall: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n", |
| 423 | p->eax, p->ebx, p->ecx, p->edx); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 424 | TRACE(int31, " ESI=%08lx EDI=%08lx ES=%04x DS=%04x CS:IP=%04x:%04x, %d WORD arguments, %s\n", |
| 425 | 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] | 426 | |
| 427 | if (!(p->cs) && !(p->ip)) { /* remove this check |
| 428 | if Int21/6501 case map function |
| 429 | has been implemented */ |
| 430 | SET_CFLAG(context); |
| 431 | return; |
| 432 | } |
| 433 | INT_GetRealModeContext(p, &context16); |
Ove Kaaven | 28c1132 | 1998-10-23 09:50:07 +0000 | [diff] [blame] | 434 | DPMI_CallRMProc( &context16, ((LPWORD)PTR_SEG_OFF_TO_LIN(SS_reg(context), SP_reg(context)))+3, |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 435 | CX_reg(context), iret ); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 436 | INT_SetRealModeContext(p, &context16); |
| 437 | } |
| 438 | |
| 439 | |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 440 | static void WINAPI RMCallbackProc( RMCB *rmcb ) |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 441 | { |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 442 | /* This routine should call DPMI_CallRMCBProc, but we don't have the |
| 443 | register structure available - this is easily fixed by going through |
| 444 | a Win16 register relay instead of calling RMCallbackProc "directly", |
| 445 | but I won't bother at this time. */ |
| 446 | FIXME(int31,"not properly supported on your architecture!\n"); |
| 447 | } |
| 448 | |
| 449 | static RMCB *DPMI_AllocRMCB( void ) |
| 450 | { |
| 451 | RMCB *NewRMCB = HeapAlloc(GetProcessHeap(), 0, sizeof(RMCB)); |
| 452 | UINT16 uParagraph; |
| 453 | |
| 454 | if (NewRMCB) |
| 455 | { |
| 456 | #ifdef MZ_SUPPORTED |
| 457 | LPVOID RMCBmem = DOSMEM_GetBlock(0, 4, &uParagraph); |
| 458 | LPBYTE p = RMCBmem; |
| 459 | |
| 460 | *p++ = 0xcd; /* RMCB: */ |
| 461 | *p++ = 0x31; /* int $0x31 */ |
| 462 | /* it is the called procedure's task to change the return CS:EIP |
| 463 | the DPMI 0.9 spec states that if it doesn't, it will be called again */ |
| 464 | *p++ = 0xeb; |
| 465 | *p++ = 0xfc; /* jmp RMCB */ |
| 466 | #else |
| 467 | LPVOID RMCBmem = DOSMEM_GetBlock(0, 15, &uParagraph); |
| 468 | LPBYTE p = RMCBmem; |
| 469 | |
| 470 | *p++ = 0x68; /* pushl */ |
| 471 | *(LPVOID *)p = NewRMCB; |
| 472 | p+=4; |
| 473 | *p++ = 0x9a; /* lcall */ |
| 474 | *(FARPROC16 *)p = (FARPROC16)RMCallbackProc; /* FIXME: register relay */ |
| 475 | p+=4; |
| 476 | GET_CS(*(WORD *)p); |
| 477 | p+=2; |
| 478 | *p++=0xc3; /* lret (FIXME?) */ |
| 479 | #endif |
| 480 | NewRMCB->address = MAKELONG(0, uParagraph); |
| 481 | NewRMCB->next = FirstRMCB; |
| 482 | FirstRMCB = NewRMCB; |
| 483 | } |
| 484 | return NewRMCB; |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 485 | } |
| 486 | |
| 487 | |
| 488 | static void AllocRMCB( CONTEXT *context ) |
| 489 | { |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 490 | RMCB *NewRMCB = DPMI_AllocRMCB(); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 491 | REALMODECALL *p = (REALMODECALL *)PTR_SEG_OFF_TO_LIN( ES_reg(context), DI_reg(context) ); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 492 | |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 493 | TRACE(int31, "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] | 494 | |
| 495 | if (NewRMCB) |
| 496 | { |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 497 | /* FIXME: if 32-bit DPMI client, use ESI and EDI */ |
| 498 | NewRMCB->proc_ofs = SI_reg(context); |
| 499 | NewRMCB->proc_sel = DS_reg(context); |
| 500 | NewRMCB->regs_ofs = DI_reg(context); |
| 501 | NewRMCB->regs_sel = ES_reg(context); |
| 502 | CX_reg(context) = HIWORD(NewRMCB->address); |
| 503 | DX_reg(context) = LOWORD(NewRMCB->address); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 504 | } |
| 505 | else |
| 506 | { |
| 507 | AX_reg(context) = 0x8015; /* callback unavailable */ |
| 508 | SET_CFLAG(context); |
| 509 | } |
| 510 | } |
| 511 | |
| 512 | |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 513 | FARPROC16 WINAPI DPMI_AllocInternalRMCB( RMCBPROC proc ) |
| 514 | { |
| 515 | RMCB *NewRMCB = DPMI_AllocRMCB(); |
| 516 | |
| 517 | if (NewRMCB) { |
| 518 | NewRMCB->proc_ofs = (DWORD)proc; |
| 519 | NewRMCB->proc_sel = 0; |
| 520 | NewRMCB->regs_ofs = 0; |
| 521 | NewRMCB->regs_sel = 0; |
| 522 | return (FARPROC16)(NewRMCB->address); |
| 523 | } |
| 524 | return NULL; |
| 525 | } |
| 526 | |
| 527 | |
| 528 | static int DPMI_FreeRMCB( DWORD address ) |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 529 | { |
| 530 | RMCB *CurrRMCB = FirstRMCB; |
| 531 | RMCB *PrevRMCB = NULL; |
| 532 | |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 533 | while (CurrRMCB && (CurrRMCB->address != address)) |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 534 | { |
| 535 | PrevRMCB = CurrRMCB; |
| 536 | CurrRMCB = CurrRMCB->next; |
| 537 | } |
| 538 | if (CurrRMCB) |
| 539 | { |
| 540 | if (PrevRMCB) |
| 541 | PrevRMCB->next = CurrRMCB->next; |
| 542 | else |
| 543 | FirstRMCB = CurrRMCB->next; |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 544 | DOSMEM_FreeBlock(0, DOSMEM_MapRealToLinear(CurrRMCB->address)); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 545 | HeapFree(GetProcessHeap(), 0, CurrRMCB); |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 546 | return 0; |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 547 | } |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 548 | return 1; |
| 549 | } |
| 550 | |
| 551 | |
| 552 | static void FreeRMCB( CONTEXT *context ) |
| 553 | { |
| 554 | FIXME(int31, "callback address: %04x:%04x\n", |
| 555 | CX_reg(context), DX_reg(context)); |
| 556 | |
| 557 | if (DPMI_FreeRMCB(MAKELONG(DX_reg(context), CX_reg(context)))) { |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 558 | AX_reg(context) = 0x8024; /* invalid callback address */ |
| 559 | SET_CFLAG(context); |
| 560 | } |
| 561 | } |
| 562 | |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 563 | |
| 564 | void WINAPI DPMI_FreeInternalRMCB( FARPROC16 proc ) |
| 565 | { |
| 566 | DPMI_FreeRMCB( (DWORD)proc ); |
| 567 | } |
| 568 | |
| 569 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 570 | #ifdef MZ_SUPPORTED |
| 571 | /* (see loader/dos/module.c, function MZ_InitDPMI) */ |
| 572 | |
| 573 | static void StartPM( CONTEXT *context, LPDOSTASK lpDosTask ) |
| 574 | { |
| 575 | char *base = DOSMEM_MemoryBase(0); |
| 576 | UINT16 cs, ss, ds, es; |
| 577 | CONTEXT pm_ctx; |
| 578 | |
| 579 | RESET_CFLAG(context); |
| 580 | lpDosTask->dpmi_flag = AX_reg(context); |
| 581 | /* our mode switch wrapper have placed the desired CS into DX */ |
| 582 | cs = SELECTOR_AllocBlock( base + (DWORD)(DX_reg(context)<<4), 0x10000, SEGMENT_CODE, FALSE, FALSE ); |
| 583 | ss = SELECTOR_AllocBlock( base + (DWORD)(SS_reg(context)<<4), 0x10000, SEGMENT_DATA, FALSE, FALSE ); |
| 584 | ds = SELECTOR_AllocBlock( base + (DWORD)(DS_reg(context)<<4), 0x10000, SEGMENT_DATA, FALSE, FALSE ); |
| 585 | es = SELECTOR_AllocBlock( base + (DWORD)(lpDosTask->psp_seg<<4), 0x100, SEGMENT_DATA, FALSE, FALSE ); |
| 586 | |
| 587 | pm_ctx = *context; |
| 588 | CS_reg(&pm_ctx) = lpDosTask->dpmi_sel; |
| 589 | /* our mode switch wrapper expects the new CS in DX, and the new SS in AX */ |
| 590 | AX_reg(&pm_ctx) = ss; |
| 591 | DX_reg(&pm_ctx) = cs; |
| 592 | DS_reg(&pm_ctx) = ds; |
| 593 | ES_reg(&pm_ctx) = es; |
| 594 | FS_reg(&pm_ctx) = 0; |
| 595 | GS_reg(&pm_ctx) = 0; |
| 596 | |
| 597 | TRACE(int31,"DOS program is now entering protected mode\n"); |
| 598 | Callbacks->CallRegisterShortProc(&pm_ctx, 0); |
| 599 | |
| 600 | /* in the current state of affairs, we won't ever actually return here... */ |
| 601 | |
| 602 | UnMapLS(PTR_SEG_OFF_TO_SEGPTR(es,0)); |
| 603 | UnMapLS(PTR_SEG_OFF_TO_SEGPTR(ds,0)); |
| 604 | UnMapLS(PTR_SEG_OFF_TO_SEGPTR(ss,0)); |
| 605 | UnMapLS(PTR_SEG_OFF_TO_SEGPTR(cs,0)); |
| 606 | } |
| 607 | #endif |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 608 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 609 | /********************************************************************** |
Alexandre Julliard | e2991ea | 1995-07-29 13:09:43 +0000 | [diff] [blame] | 610 | * INT_Int31Handler |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 611 | * |
Alexandre Julliard | e2991ea | 1995-07-29 13:09:43 +0000 | [diff] [blame] | 612 | * Handler for int 31h (DPMI). |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 613 | */ |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 614 | |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 615 | void WINAPI INT_Int31Handler( CONTEXT *context ) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 616 | { |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 617 | /* |
| 618 | * Note: For Win32s processes, the whole linear address space is |
| 619 | * shifted by 0x10000 relative to the OS linear address space. |
| 620 | * See the comment in msdos/vxd.c. |
| 621 | */ |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 622 | DWORD offset = W32S_APPLICATION() ? W32S_OFFSET : 0; |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 623 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 624 | DWORD dw; |
| 625 | BYTE *ptr; |
| 626 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 627 | TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() ); |
| 628 | NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL; |
| 629 | |
| 630 | GlobalUnlock16( GetCurrentTask() ); |
| 631 | |
| 632 | #ifdef MZ_SUPPORTED |
| 633 | if (ISV86(context) && pModule && pModule->lpDosTask) { |
| 634 | /* Called from real mode, check if it's our wrapper */ |
| 635 | TRACE(int31,"called from real mode\n"); |
| 636 | if (CS_reg(context)==pModule->lpDosTask->dpmi_seg) { |
| 637 | /* This is the protected mode switch */ |
| 638 | StartPM(context,pModule->lpDosTask); |
| 639 | return; |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 640 | } else |
| 641 | if (CS_reg(context)==pModule->lpDosTask->xms_seg) { |
| 642 | /* This is the XMS driver entry point */ |
| 643 | XMS_Handler(context); |
| 644 | return; |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 645 | } else |
| 646 | { |
| 647 | /* Check for RMCB */ |
| 648 | RMCB *CurrRMCB = FirstRMCB; |
| 649 | |
| 650 | while (CurrRMCB && (HIWORD(CurrRMCB->address) != CS_reg(context))) |
| 651 | CurrRMCB = CurrRMCB->next; |
| 652 | |
| 653 | if (CurrRMCB) { |
| 654 | /* RMCB call, propagate to protected-mode handler */ |
| 655 | DPMI_CallRMCBProc(context, CurrRMCB, pModule->lpDosTask->dpmi_flag); |
| 656 | return; |
| 657 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 658 | } |
| 659 | } |
| 660 | #endif |
| 661 | |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 662 | RESET_CFLAG(context); |
| 663 | switch(AX_reg(context)) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 664 | { |
| 665 | case 0x0000: /* Allocate LDT descriptors */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 666 | TRACE(int31,"allocate LDT descriptors (%d)\n",CX_reg(context)); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 667 | if (!(AX_reg(context) = AllocSelectorArray( CX_reg(context) ))) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 668 | { |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 669 | TRACE(int31,"failed\n"); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 670 | AX_reg(context) = 0x8011; /* descriptor unavailable */ |
| 671 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 672 | } |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 673 | TRACE(int31,"success, array starts at 0x%04x\n",AX_reg(context)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 674 | break; |
| 675 | |
| 676 | case 0x0001: /* Free LDT descriptor */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 677 | TRACE(int31,"free LDT descriptor (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 678 | if (FreeSelector( BX_reg(context) )) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 679 | { |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 680 | AX_reg(context) = 0x8022; /* invalid selector */ |
| 681 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 682 | } |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 683 | else |
| 684 | { |
| 685 | /* If a segment register contains the selector being freed, */ |
| 686 | /* set it to zero. */ |
| 687 | if (!((DS_reg(context)^BX_reg(context)) & ~3)) DS_reg(context) = 0; |
| 688 | if (!((ES_reg(context)^BX_reg(context)) & ~3)) ES_reg(context) = 0; |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 689 | if (!((FS_reg(context)^BX_reg(context)) & ~3)) FS_reg(context) = 0; |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 690 | if (!((GS_reg(context)^BX_reg(context)) & ~3)) GS_reg(context) = 0; |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 691 | } |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 692 | break; |
| 693 | |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 694 | case 0x0002: /* Real mode segment to descriptor */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 695 | TRACE(int31,"real mode segment to descriptor (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 696 | { |
| 697 | WORD entryPoint = 0; /* KERNEL entry point for descriptor */ |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 698 | switch(BX_reg(context)) |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 699 | { |
| 700 | case 0x0000: entryPoint = 183; break; /* __0000H */ |
| 701 | case 0x0040: entryPoint = 193; break; /* __0040H */ |
| 702 | case 0xa000: entryPoint = 174; break; /* __A000H */ |
| 703 | case 0xb000: entryPoint = 181; break; /* __B000H */ |
| 704 | case 0xb800: entryPoint = 182; break; /* __B800H */ |
| 705 | case 0xc000: entryPoint = 195; break; /* __C000H */ |
| 706 | case 0xd000: entryPoint = 179; break; /* __D000H */ |
| 707 | case 0xe000: entryPoint = 190; break; /* __E000H */ |
| 708 | case 0xf000: entryPoint = 194; break; /* __F000H */ |
| 709 | default: |
Alexandre Julliard | ac9c9b0 | 1996-07-28 18:50:11 +0000 | [diff] [blame] | 710 | AX_reg(context) = DOSMEM_AllocSelector(BX_reg(context)); |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 711 | break; |
| 712 | } |
| 713 | if (entryPoint) |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 714 | AX_reg(context) = LOWORD(NE_GetEntryPoint( |
Alexandre Julliard | 2197901 | 1997-03-05 08:22:35 +0000 | [diff] [blame] | 715 | GetModuleHandle16( "KERNEL" ), |
| 716 | entryPoint )); |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 717 | } |
| 718 | break; |
| 719 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 720 | case 0x0003: /* Get next selector increment */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 721 | TRACE(int31,"get selector increment (__AHINCR)\n"); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 722 | AX_reg(context) = __AHINCR; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 723 | break; |
| 724 | |
| 725 | case 0x0004: /* Lock selector (not supported) */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 726 | FIXME(int31,"lock selector not supported\n"); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 727 | AX_reg(context) = 0; /* FIXME: is this a correct return value? */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 728 | break; |
| 729 | |
| 730 | case 0x0005: /* Unlock selector (not supported) */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 731 | FIXME(int31,"unlock selector not supported\n"); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 732 | AX_reg(context) = 0; /* FIXME: is this a correct return value? */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 733 | break; |
| 734 | |
| 735 | case 0x0006: /* Get selector base address */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 736 | TRACE(int31,"get selector base address (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 737 | if (!(dw = GetSelectorBase( BX_reg(context) ))) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 738 | { |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 739 | AX_reg(context) = 0x8022; /* invalid selector */ |
| 740 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 741 | } |
| 742 | else |
| 743 | { |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 744 | #ifdef MZ_SUPPORTED |
| 745 | if (pModule && pModule->lpDosTask) { |
| 746 | DWORD base = (DWORD)DOSMEM_MemoryBase(pModule->self); |
| 747 | if ((dw >= base) && (dw < base + 0x110000)) dw -= base; |
| 748 | } |
| 749 | #endif |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 750 | CX_reg(context) = HIWORD(W32S_WINE2APP(dw, offset)); |
| 751 | DX_reg(context) = LOWORD(W32S_WINE2APP(dw, offset)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 752 | } |
| 753 | break; |
| 754 | |
| 755 | case 0x0007: /* Set selector base address */ |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 756 | TRACE(int31, "set selector base address (0x%04x,0x%08lx)\n", |
| 757 | BX_reg(context), |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 758 | W32S_APP2WINE(MAKELONG(DX_reg(context),CX_reg(context)), offset)); |
| 759 | dw = W32S_APP2WINE(MAKELONG(DX_reg(context), CX_reg(context)), offset); |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 760 | #ifdef MZ_SUPPORTED |
| 761 | /* well, what else could we possibly do? */ |
| 762 | if (pModule && pModule->lpDosTask) { |
| 763 | if (dw < 0x110000) dw += (DWORD)DOSMEM_MemoryBase(pModule->self); |
| 764 | } |
| 765 | #endif |
| 766 | SetSelectorBase(BX_reg(context), dw); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 767 | break; |
| 768 | |
| 769 | case 0x0008: /* Set selector limit */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 770 | TRACE(int31,"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] | 771 | dw = MAKELONG( DX_reg(context), CX_reg(context) ); |
| 772 | #ifdef MZ_SUPPORTED |
| 773 | if (pModule && pModule->lpDosTask) { |
| 774 | DWORD base = GetSelectorBase( BX_reg(context) ); |
| 775 | if ((dw == 0xffffffff) || ((base < 0x110000) && (base + dw > 0x110000))) { |
| 776 | AX_reg(context) = 0x8021; /* invalid value */ |
| 777 | SET_CFLAG(context); |
| 778 | break; |
| 779 | } |
| 780 | } |
| 781 | #endif |
| 782 | SetSelectorLimit( BX_reg(context), dw ); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 783 | break; |
| 784 | |
| 785 | case 0x0009: /* Set selector access rights */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 786 | TRACE(int31,"set selector access rights(0x%04x,0x%04x)\n",BX_reg(context),CX_reg(context)); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 787 | SelectorAccessRights( BX_reg(context), 1, CX_reg(context) ); |
Alexandre Julliard | 18f92e7 | 1996-07-17 20:02:21 +0000 | [diff] [blame] | 788 | break; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 789 | |
| 790 | case 0x000a: /* Allocate selector alias */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 791 | TRACE(int31,"allocate selector alias (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 792 | if (!(AX_reg(context) = AllocCStoDSAlias( BX_reg(context) ))) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 793 | { |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 794 | AX_reg(context) = 0x8011; /* descriptor unavailable */ |
| 795 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 796 | } |
| 797 | break; |
| 798 | |
| 799 | case 0x000b: /* Get descriptor */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 800 | TRACE(int31,"get descriptor (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 801 | { |
| 802 | ldt_entry entry; |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 803 | LDT_GetEntry( SELECTOR_TO_ENTRY( BX_reg(context) ), &entry ); |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 804 | entry.base = W32S_WINE2APP(entry.base, offset); |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 805 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 806 | /* FIXME: should use ES:EDI for 32-bit clients */ |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 807 | LDT_EntryToBytes( PTR_SEG_OFF_TO_LIN( ES_reg(context), |
| 808 | DI_reg(context) ), &entry ); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 809 | } |
| 810 | break; |
| 811 | |
| 812 | case 0x000c: /* Set descriptor */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 813 | TRACE(int31,"set descriptor (0x%04x)\n",BX_reg(context)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 814 | { |
| 815 | ldt_entry entry; |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 816 | LDT_BytesToEntry( PTR_SEG_OFF_TO_LIN( ES_reg(context), |
| 817 | DI_reg(context) ), &entry ); |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 818 | entry.base = W32S_APP2WINE(entry.base, offset); |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 819 | |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 820 | LDT_SetEntry( SELECTOR_TO_ENTRY( BX_reg(context) ), &entry ); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 821 | } |
| 822 | break; |
| 823 | |
| 824 | case 0x000d: /* Allocate specific LDT descriptor */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 825 | FIXME(int31,"allocate descriptor (0x%04x), stub!\n",BX_reg(context)); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 826 | AX_reg(context) = 0x8011; /* descriptor unavailable */ |
| 827 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 828 | break; |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 829 | case 0x0100: /* Allocate DOS memory block */ |
| 830 | TRACE(int31,"allocate DOS memory block (0x%x paragraphs)\n",BX_reg(context)); |
| 831 | dw = GlobalDOSAlloc((DWORD)BX_reg(context)<<4); |
| 832 | if (dw) { |
| 833 | AX_reg(context) = HIWORD(dw); |
| 834 | DX_reg(context) = LOWORD(dw); |
| 835 | } else { |
| 836 | AX_reg(context) = 0x0008; /* insufficient memory */ |
| 837 | BX_reg(context) = DOSMEM_Available(0)>>4; |
| 838 | SET_CFLAG(context); |
| 839 | } |
| 840 | break; |
| 841 | case 0x0101: /* Free DOS memory block */ |
| 842 | TRACE(int31,"free DOS memory block (0x%04x)\n",DX_reg(context)); |
| 843 | dw = GlobalDOSFree(DX_reg(context)); |
| 844 | if (!dw) { |
| 845 | AX_reg(context) = 0x0009; /* memory block address invalid */ |
| 846 | SET_CFLAG(context); |
| 847 | } |
| 848 | break; |
Alexandre Julliard | 2c69f6d | 1996-09-28 18:11:01 +0000 | [diff] [blame] | 849 | case 0x0200: /* get real mode interrupt vector */ |
Alexandre Julliard | 54c2711 | 1998-03-29 19:44:57 +0000 | [diff] [blame] | 850 | FIXME(int31,"get realmode interupt vector(0x%02x) unimplemented.\n", |
| 851 | BL_reg(context)); |
Alexandre Julliard | 2c69f6d | 1996-09-28 18:11:01 +0000 | [diff] [blame] | 852 | SET_CFLAG(context); |
| 853 | break; |
| 854 | case 0x0201: /* set real mode interrupt vector */ |
Alexandre Julliard | 54c2711 | 1998-03-29 19:44:57 +0000 | [diff] [blame] | 855 | FIXME(int31, "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] | 856 | SET_CFLAG(context); |
| 857 | break; |
Alexandre Julliard | e2991ea | 1995-07-29 13:09:43 +0000 | [diff] [blame] | 858 | case 0x0204: /* Get protected mode interrupt vector */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 859 | TRACE(int31,"get protected mode interrupt handler (0x%02x), stub!\n",BL_reg(context)); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 860 | dw = (DWORD)INT_GetPMHandler( BL_reg(context) ); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 861 | CX_reg(context) = HIWORD(dw); |
| 862 | DX_reg(context) = LOWORD(dw); |
Alexandre Julliard | e2991ea | 1995-07-29 13:09:43 +0000 | [diff] [blame] | 863 | break; |
| 864 | |
| 865 | case 0x0205: /* Set protected mode interrupt vector */ |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 866 | TRACE(int31,"set protected mode interrupt handler (0x%02x,%p), stub!\n", |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 867 | 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] | 868 | INT_SetPMHandler( BL_reg(context), |
| 869 | (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( CX_reg(context), |
| 870 | DX_reg(context) )); |
Alexandre Julliard | e2991ea | 1995-07-29 13:09:43 +0000 | [diff] [blame] | 871 | break; |
| 872 | |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 873 | case 0x0300: /* Simulate real mode interrupt */ |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 874 | CallRMInt( context ); |
Alexandre Julliard | d7d4fdf | 1995-12-26 15:05:24 +0000 | [diff] [blame] | 875 | break; |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 876 | |
Alexandre Julliard | d7d4fdf | 1995-12-26 15:05:24 +0000 | [diff] [blame] | 877 | case 0x0301: /* Call real mode procedure with far return */ |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 878 | CallRMProc( context, FALSE ); |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 879 | break; |
Alexandre Julliard | d7d4fdf | 1995-12-26 15:05:24 +0000 | [diff] [blame] | 880 | |
| 881 | case 0x0302: /* Call real mode procedure with interrupt return */ |
Ove Kaaven | 2866809 | 1998-12-09 13:14:19 +0000 | [diff] [blame^] | 882 | CallRMProc( context, TRUE ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 883 | break; |
| 884 | |
Alexandre Julliard | ac9c9b0 | 1996-07-28 18:50:11 +0000 | [diff] [blame] | 885 | case 0x0303: /* Allocate Real Mode Callback Address */ |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 886 | AllocRMCB( context ); |
| 887 | break; |
Alexandre Julliard | ac9c9b0 | 1996-07-28 18:50:11 +0000 | [diff] [blame] | 888 | |
Alexandre Julliard | 60ce85c | 1998-02-01 18:33:27 +0000 | [diff] [blame] | 889 | case 0x0304: /* Free Real Mode Callback Address */ |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 890 | FreeRMCB( context ); |
Alexandre Julliard | 60ce85c | 1998-02-01 18:33:27 +0000 | [diff] [blame] | 891 | break; |
| 892 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 893 | case 0x0400: /* Get DPMI version */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 894 | TRACE(int31,"get DPMI version\n"); |
Alexandre Julliard | 349a953 | 1997-02-02 19:01:52 +0000 | [diff] [blame] | 895 | { |
| 896 | SYSTEM_INFO si; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 897 | |
Alexandre Julliard | 349a953 | 1997-02-02 19:01:52 +0000 | [diff] [blame] | 898 | GetSystemInfo(&si); |
| 899 | AX_reg(context) = 0x005a; /* DPMI version 0.90 */ |
| 900 | BX_reg(context) = 0x0005; /* Flags: 32-bit, virtual memory */ |
| 901 | CL_reg(context) = si.wProcessorLevel; |
| 902 | DX_reg(context) = 0x0102; /* Master/slave interrupt controller base*/ |
| 903 | break; |
| 904 | } |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 905 | case 0x0500: /* Get free memory information */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 906 | TRACE(int31,"get free memory information\n"); |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 907 | { |
| 908 | MEMMANINFO mmi; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 909 | |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 910 | mmi.dwSize = sizeof(mmi); |
| 911 | MemManInfo(&mmi); |
| 912 | ptr = (BYTE *)PTR_SEG_OFF_TO_LIN(ES_reg(context),DI_reg(context)); |
| 913 | /* the layout is just the same as MEMMANINFO, but without |
| 914 | * the dwSize entry. |
| 915 | */ |
| 916 | memcpy(ptr,((char*)&mmi)+4,sizeof(mmi)-4); |
| 917 | break; |
| 918 | } |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 919 | case 0x0501: /* Allocate memory block */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 920 | TRACE(int31,"allocate memory block (%ld)\n",MAKELONG(CX_reg(context),BX_reg(context))); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 921 | if (!(ptr = (BYTE *)DPMI_xalloc(MAKELONG(CX_reg(context), BX_reg(context))))) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 922 | { |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 923 | AX_reg(context) = 0x8012; /* linear memory not available */ |
| 924 | SET_CFLAG(context); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 925 | } else { |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 926 | BX_reg(context) = SI_reg(context) = HIWORD(W32S_WINE2APP(ptr, offset)); |
| 927 | CX_reg(context) = DI_reg(context) = LOWORD(W32S_WINE2APP(ptr, offset)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 928 | } |
| 929 | break; |
| 930 | |
| 931 | case 0x0502: /* Free memory block */ |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 932 | TRACE(int31, "free memory block (0x%08lx)\n", |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 933 | W32S_APP2WINE(MAKELONG(DI_reg(context),SI_reg(context)), offset)); |
| 934 | DPMI_xfree( (void *)W32S_APP2WINE(MAKELONG(DI_reg(context), |
| 935 | SI_reg(context)), offset) ); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 936 | break; |
| 937 | |
| 938 | case 0x0503: /* Resize memory block */ |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 939 | TRACE(int31, "resize memory block (0x%08lx,%ld)\n", |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 940 | W32S_APP2WINE(MAKELONG(DI_reg(context),SI_reg(context)), offset), |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 941 | MAKELONG(CX_reg(context),BX_reg(context))); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 942 | if (!(ptr = (BYTE *)DPMI_xrealloc( |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 943 | (void *)W32S_APP2WINE(MAKELONG(DI_reg(context),SI_reg(context)), offset), |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 944 | MAKELONG(CX_reg(context),BX_reg(context))))) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 945 | { |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 946 | AX_reg(context) = 0x8012; /* linear memory not available */ |
| 947 | SET_CFLAG(context); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 948 | } else { |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 949 | BX_reg(context) = SI_reg(context) = HIWORD(W32S_WINE2APP(ptr, offset)); |
| 950 | CX_reg(context) = DI_reg(context) = LOWORD(W32S_WINE2APP(ptr, offset)); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 951 | } |
| 952 | break; |
| 953 | |
Ove Kaaven | a7cf4ee | 1998-10-11 12:26:00 +0000 | [diff] [blame] | 954 | case 0x0507: /* Modify page attributes */ |
| 955 | FIXME(int31,"modify page attributes unimplemented\n"); |
| 956 | break; /* Just ignore it */ |
| 957 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 958 | case 0x0600: /* Lock linear region */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 959 | FIXME(int31,"lock linear region unimplemented\n"); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 960 | break; /* Just ignore it */ |
| 961 | |
| 962 | case 0x0601: /* Unlock linear region */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 963 | FIXME(int31,"unlock linear region unimplemented\n"); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 964 | break; /* Just ignore it */ |
| 965 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 966 | case 0x0602: /* Unlock real-mode region */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 967 | FIXME(int31,"unlock realmode region unimplemented\n"); |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 968 | break; /* Just ignore it */ |
| 969 | |
| 970 | case 0x0603: /* Lock real-mode region */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 971 | FIXME(int31,"lock realmode region unimplemented\n"); |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 972 | break; /* Just ignore it */ |
| 973 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 974 | case 0x0604: /* Get page size */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 975 | TRACE(int31,"get pagesize\n"); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 976 | BX_reg(context) = 0; |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 977 | CX_reg(context) = VIRTUAL_GetPageSize(); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 978 | break; |
| 979 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 980 | case 0x0702: /* Mark page as demand-paging candidate */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 981 | FIXME(int31,"mark page as demand-paging candidate\n"); |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 982 | break; /* Just ignore it */ |
| 983 | |
| 984 | case 0x0703: /* Discard page contents */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 985 | FIXME(int31,"discard page contents\n"); |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 986 | break; /* Just ignore it */ |
| 987 | |
Alexandre Julliard | 03468f7 | 1998-02-15 19:40:49 +0000 | [diff] [blame] | 988 | case 0x0800: /* Physical address mapping */ |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 989 | FIXME(int31,"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] | 990 | if(!(ptr=DOSMEM_MapRealToLinear(MAKELONG(CX_reg(context),BX_reg(context))))) |
| 991 | { |
| 992 | AX_reg(context) = 0x8021; |
| 993 | SET_CFLAG(context); |
| 994 | } |
| 995 | else |
| 996 | { |
Andreas Mohr | a00b49f | 1998-12-07 10:48:09 +0000 | [diff] [blame] | 997 | BX_reg(context) = HIWORD(W32S_WINE2APP(ptr, offset)); |
| 998 | CX_reg(context) = LOWORD(W32S_WINE2APP(ptr, offset)); |
Alexandre Julliard | 03468f7 | 1998-02-15 19:40:49 +0000 | [diff] [blame] | 999 | RESET_CFLAG(context); |
| 1000 | } |
| 1001 | break; |
| 1002 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1003 | default: |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1004 | INT_BARF( context, 0x31 ); |
| 1005 | AX_reg(context) = 0x8001; /* unsupported function */ |
| 1006 | SET_CFLAG(context); |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1007 | break; |
| 1008 | } |
Alexandre Julliard | 642d313 | 1998-07-12 19:29:36 +0000 | [diff] [blame] | 1009 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1010 | } |