4 * Copyright 1998 Ove Kåven
5 * Copyright 2002 Jukka Heinonen
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * Note: This code hasn't been completely cleaned up yet.
25 #include "wine/port.h"
37 #ifdef HAVE_SYS_TIME_H
38 # include <sys/time.h>
40 #include <sys/types.h>
42 #include "wine/winbase16.h"
43 #include "wine/exception.h"
54 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(int);
60 WORD DOSVM_retval
= 0;
63 * Wine DOS memory layout above 640k:
65 * a0000 - affff : VGA graphics (vga.c)
66 * b0000 - bffff : Monochrome text (unused)
67 * b8000 - bffff : VGA text (vga.c)
68 * c0000 - cffff : EMS frame (int67.c)
69 * d0000 - effff : Free memory for UMBs (himem.c)
70 * f0000 - fffff : BIOS stuff (msdos/dosmem.c)
71 * 100000 -10ffff : High memory area (unused)
75 * Table of real mode segments and protected mode selectors
76 * for code stubs and other miscellaneous storage.
78 struct DPMI_segments
*DOSVM_dpmi_segments
= NULL
;
81 * First and last address available for upper memory blocks.
83 #define DOSVM_UMB_BOTTOM 0xd0000
84 #define DOSVM_UMB_TOP 0xeffff
87 * First free address for upper memory blocks.
89 static DWORD DOSVM_umb_free
= DOSVM_UMB_BOTTOM
;
92 /**********************************************************************
95 void DOSVM_Exit( WORD retval
)
99 ReleaseThunkLock( &count
);
100 ExitThread( retval
);
103 /***********************************************************************
106 * Allocate upper memory block (UMB) from upper memory.
107 * Returned pointer is aligned to 16-byte (paragraph) boundary.
109 * This routine is only for allocating static storage for
110 * Wine internal uses. Allocated memory can be accessed from
111 * real mode, memory is taken from area already mapped and reserved
112 * by Wine and the allocation has very little memory and speed
113 * overhead. Use of this routine also preserves precious DOS
114 * conventional memory.
116 static LPVOID
DOSVM_AllocUMB( DWORD size
)
118 LPVOID ptr
= (LPVOID
)DOSVM_umb_free
;
120 size
= ((size
+ 15) >> 4) << 4;
122 if(DOSVM_umb_free
+ size
- 1 > DOSVM_UMB_TOP
) {
123 ERR("Out of upper memory area.\n");
127 DOSVM_umb_free
+= size
;
132 /**********************************************************************
135 * Allocate a selector corresponding to a real mode address.
136 * size must be < 64k.
138 static WORD
alloc_selector( void *base
, DWORD size
, unsigned char flags
)
140 WORD sel
= wine_ldt_alloc_entries( 1 );
145 wine_ldt_set_base( &entry
, base
);
146 wine_ldt_set_limit( &entry
, size
- 1 );
147 wine_ldt_set_flags( &entry
, flags
);
148 wine_ldt_set_entry( sel
, &entry
);
154 /***********************************************************************
157 * Allocate upper memory block for storing code stubs.
158 * Initializes real mode segment and 16-bit protected mode selector
159 * for the allocated code block.
161 * FIXME: should allocate a single PM selector for the whole UMB range.
163 static LPVOID
DOSVM_AllocCodeUMB( DWORD size
, WORD
*selector
)
165 LPVOID ptr
= DOSVM_AllocUMB( size
);
166 *selector
= alloc_selector( ptr
, size
, WINE_LDT_FLAGS_CODE
);
171 /***********************************************************************
174 * Allocate upper memory block for storing data.
175 * Initializes real mode segment and 16-bit protected mode selector
176 * for the allocated data block.
178 LPVOID
DOSVM_AllocDataUMB( DWORD size
, WORD
*selector
)
180 LPVOID ptr
= DOSVM_AllocUMB( size
);
181 *selector
= alloc_selector( ptr
, size
, WINE_LDT_FLAGS_DATA
);
186 /***********************************************************************
189 * Initializes DOSVM_dpmi_segments. Allocates required memory and
190 * sets up segments and selectors for accessing the memory.
192 void DOSVM_InitSegments(void)
198 static const char relay
[]=
200 0xca, 0x04, 0x00, /* 16-bit far return and pop 4 bytes (relay void* arg) */
201 0xcd, 0x31, /* int 31 */
202 0xfb, 0x66, 0xcb /* sti and 32-bit far return */
206 * Allocate pointer array.
208 DOSVM_dpmi_segments
= DOSVM_AllocUMB( sizeof(struct DPMI_segments
) );
211 * PM / offset N*5: Interrupt N in 16-bit protected mode.
213 ptr
= DOSVM_AllocCodeUMB( 5 * 256, &DOSVM_dpmi_segments
->int16_sel
);
214 for(i
=0; i
<256; i
++) {
216 * Each 16-bit interrupt handler is 5 bytes:
217 * 0xCD,<i> = int <i> (interrupt)
218 * 0xCA,0x02,0x00 = ret 2 (16-bit far return and pop 2 bytes / eflags)
220 ptr
[i
* 5 + 0] = 0xCD;
222 ptr
[i
* 5 + 2] = 0xCA;
223 ptr
[i
* 5 + 3] = 0x02;
224 ptr
[i
* 5 + 4] = 0x00;
228 * PM / offset 0: Stub where __wine_call_from_16_regs returns.
229 * PM / offset 3: Stub which swaps back to 32-bit application code/stack.
230 * PM / offset 5: Stub which enables interrupts
232 ptr
= DOSVM_AllocCodeUMB( sizeof(relay
), &DOSVM_dpmi_segments
->relay_code_sel
);
233 memcpy( ptr
, relay
, sizeof(relay
) );
236 * Space for 16-bit stack used by relay code.
238 ptr
= DOSVM_AllocDataUMB( DOSVM_RELAY_DATA_SIZE
, &DOSVM_dpmi_segments
->relay_data_sel
);
239 memset( ptr
, 0, DOSVM_RELAY_DATA_SIZE
);
242 * As we store code in UMB we should make sure it is executable
244 VirtualProtect((void *)DOSVM_UMB_BOTTOM
, DOSVM_UMB_TOP
- DOSVM_UMB_BOTTOM
, PAGE_EXECUTE_READWRITE
, &old_prot
);