diff --git a/dlls/winedos/Makefile.in b/dlls/winedos/Makefile.in index 52b81739287..208968e7cba 100644 --- a/dlls/winedos/Makefile.in +++ b/dlls/winedos/Makefile.in @@ -13,7 +13,6 @@ C_SRCS = \ dosmem.c \ dosvm.c \ fpu.c \ - himem.c \ int09.c \ int10.c \ int13.c \ diff --git a/dlls/winedos/dosexe.h b/dlls/winedos/dosexe.h index 52a1988f039..1a9b593ef1f 100644 --- a/dlls/winedos/dosexe.h +++ b/dlls/winedos/dosexe.h @@ -362,6 +362,7 @@ extern DWORD DOSVM_Loop( HANDLE hThread ); extern void DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data ); extern void DOSVM_PIC_ioport_out( WORD port, BYTE val ); extern void DOSVM_SetTimer( UINT ticks ); +extern LPVOID DOSVM_AllocDataUMB(DWORD, WORD *, WORD *); /* devices.c */ extern void DOSDEV_InstallDOSDevices(void); @@ -404,10 +405,6 @@ extern void WINAPI DOSVM_Int3cHandler(CONTEXT86*); extern void WINAPI DOSVM_Int3dHandler(CONTEXT86*); extern void WINAPI DOSVM_Int3eHandler(CONTEXT86*); -/* himem.c */ -extern void DOSVM_InitSegments(void); -extern LPVOID DOSVM_AllocDataUMB(DWORD, WORD *, WORD *); - /* int09.c */ extern void WINAPI DOSVM_Int09Handler(CONTEXT86*); extern void DOSVM_Int09SendScan(BYTE scan,BYTE ascii); diff --git a/dlls/winedos/dosvm.c b/dlls/winedos/dosvm.c index 49c2fe20ecc..05c937133b2 100644 --- a/dlls/winedos/dosvm.c +++ b/dlls/winedos/dosvm.c @@ -2,6 +2,7 @@ * DOS Virtual Machine * * Copyright 1998 Ove Kåven + * Copyright 2002 Jukka Heinonen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -63,9 +64,34 @@ WINE_DECLARE_DEBUG_CHANNEL(relay); WORD DOSVM_psp = 0; WORD DOSVM_retval = 0; -#ifdef HAVE_SYS_MMAN_H -# include -#endif +/* + * Wine DOS memory layout above 640k: + * + * a0000 - affff : VGA graphics (vga.c) + * b0000 - bffff : Monochrome text (unused) + * b8000 - bffff : VGA text (vga.c) + * c0000 - cffff : EMS frame (int67.c) + * d0000 - effff : Free memory for UMBs (himem.c) + * f0000 - fffff : BIOS stuff (msdos/dosmem.c) + * 100000 -10ffff : High memory area (unused) + */ + +/* + * Table of real mode segments and protected mode selectors + * for code stubs and other miscellaneous storage. + */ +struct DPMI_segments *DOSVM_dpmi_segments = NULL; + +/* + * First and last address available for upper memory blocks. + */ +#define DOSVM_UMB_BOTTOM 0xd0000 +#define DOSVM_UMB_TOP 0xeffff + +/* + * First free address for upper memory blocks. + */ +static DWORD DOSVM_umb_free = DOSVM_UMB_BOTTOM; typedef struct _DOSEVENT { @@ -699,6 +725,252 @@ void WINAPI DOSVM_AcknowledgeIRQ( CONTEXT86 *context ) } +/*********************************************************************** + * DOSVM_AllocUMB + * + * Allocate upper memory block (UMB) from upper memory. + * Returned pointer is aligned to 16-byte (paragraph) boundary. + * + * This routine is only for allocating static storage for + * Wine internal uses. Allocated memory can be accessed from + * real mode, memory is taken from area already mapped and reserved + * by Wine and the allocation has very little memory and speed + * overhead. Use of this routine also preserves precious DOS + * conventional memory. + */ +static LPVOID DOSVM_AllocUMB( DWORD size ) +{ + LPVOID ptr = (LPVOID)DOSVM_umb_free; + + size = ((size + 15) >> 4) << 4; + + if(DOSVM_umb_free + size - 1 > DOSVM_UMB_TOP) { + ERR("Out of upper memory area.\n"); + return 0; + } + + DOSVM_umb_free += size; + return ptr; +} + + +/********************************************************************** + * alloc_selector + * + * Allocate a selector corresponding to a real mode address. + * size must be < 64k. + */ +static WORD alloc_selector( void *base, DWORD size, unsigned char flags ) +{ + WORD sel = wine_ldt_alloc_entries( 1 ); + + if (sel) + { + LDT_ENTRY entry; + wine_ldt_set_base( &entry, base ); + wine_ldt_set_limit( &entry, size - 1 ); + wine_ldt_set_flags( &entry, flags ); + wine_ldt_set_entry( sel, &entry ); + } + return sel; +} + + +/*********************************************************************** + * DOSVM_AllocCodeUMB + * + * Allocate upper memory block for storing code stubs. + * Initializes real mode segment and 16-bit protected mode selector + * for the allocated code block. + * + * FIXME: should allocate a single PM selector for the whole UMB range. + */ +static LPVOID DOSVM_AllocCodeUMB( DWORD size, WORD *segment, WORD *selector ) +{ + LPVOID ptr = DOSVM_AllocUMB( size ); + + if (segment) + *segment = (DWORD)ptr >> 4; + + if (selector) + *selector = alloc_selector( ptr, size, WINE_LDT_FLAGS_CODE ); + + return ptr; +} + + +/*********************************************************************** + * DOSVM_AllocDataUMB + * + * Allocate upper memory block for storing data. + * Initializes real mode segment and 16-bit protected mode selector + * for the allocated data block. + */ +LPVOID DOSVM_AllocDataUMB( DWORD size, WORD *segment, WORD *selector ) +{ + LPVOID ptr = DOSVM_AllocUMB( size ); + + if (segment) + *segment = (DWORD)ptr >> 4; + + if (selector) + *selector = alloc_selector( ptr, size, WINE_LDT_FLAGS_DATA ); + + return ptr; +} + + +/*********************************************************************** + * DOSVM_InitSegments + * + * Initializes DOSVM_dpmi_segments. Allocates required memory and + * sets up segments and selectors for accessing the memory. + */ +static void DOSVM_InitSegments(void) +{ + LPSTR ptr; + int i; + + static const char wrap_code[]={ + 0xCD,0x31, /* int $0x31 */ + 0xCB /* lret */ + }; + + static const char enter_xms[]= + { + /* XMS hookable entry point */ + 0xEB,0x03, /* jmp entry */ + 0x90,0x90,0x90, /* nop;nop;nop */ + /* entry: */ + /* real entry point */ + /* for simplicity, we'll just use the same hook as DPMI below */ + 0xCD,0x31, /* int $0x31 */ + 0xCB /* lret */ + }; + + static const char enter_pm[]= + { + 0x50, /* pushw %ax */ + 0x52, /* pushw %dx */ + 0x55, /* pushw %bp */ + 0x89,0xE5, /* movw %sp,%bp */ + /* get return CS */ + 0x8B,0x56,0x08, /* movw 8(%bp),%dx */ + /* just call int 31 here to get into protected mode... */ + /* it'll check whether it was called from dpmi_seg... */ + 0xCD,0x31, /* int $0x31 */ + /* we are now in the context of a 16-bit relay call */ + /* need to fixup our stack; + * 16-bit relay return address will be lost, + * but we won't worry quite yet + */ + 0x8E,0xD0, /* movw %ax,%ss */ + 0x66,0x0F,0xB7,0xE5, /* movzwl %bp,%esp */ + /* set return CS */ + 0x89,0x56,0x08, /* movw %dx,8(%bp) */ + 0x5D, /* popw %bp */ + 0x5A, /* popw %dx */ + 0x58, /* popw %ax */ + 0xfb, /* sti, enable and check virtual interrupts */ + 0xCB /* lret */ + }; + + static const char relay[]= + { + 0xca, 0x04, 0x00, /* 16-bit far return and pop 4 bytes (relay void* arg) */ + 0xcd, 0x31, /* int 31 */ + 0xfb, 0x66, 0xcb /* sti and 32-bit far return */ + }; + + /* + * Allocate pointer array. + */ + DOSVM_dpmi_segments = DOSVM_AllocUMB( sizeof(struct DPMI_segments) ); + + /* + * RM / offset 0: Exit from real mode. + * RM / offset 2: Points to lret opcode. + */ + ptr = DOSVM_AllocCodeUMB( sizeof(wrap_code), + &DOSVM_dpmi_segments->wrap_seg, 0 ); + memcpy( ptr, wrap_code, sizeof(wrap_code) ); + + /* + * RM / offset 0: XMS driver entry. + */ + ptr = DOSVM_AllocCodeUMB( sizeof(enter_xms), + &DOSVM_dpmi_segments->xms_seg, 0 ); + memcpy( ptr, enter_xms, sizeof(enter_xms) ); + + /* + * RM / offset 0: Switch to DPMI. + * PM / offset 8: DPMI raw mode switch. + */ + ptr = DOSVM_AllocCodeUMB( sizeof(enter_pm), + &DOSVM_dpmi_segments->dpmi_seg, + &DOSVM_dpmi_segments->dpmi_sel ); + memcpy( ptr, enter_pm, sizeof(enter_pm) ); + + /* + * PM / offset N*6: Interrupt N in DPMI32. + */ + ptr = DOSVM_AllocCodeUMB( 6 * 256, + 0, &DOSVM_dpmi_segments->int48_sel ); + for(i=0; i<256; i++) { + /* + * Each 32-bit interrupt handler is 6 bytes: + * 0xCD, = int (nested 16-bit interrupt) + * 0x66,0xCA,0x04,0x00 = ret 4 (32-bit far return and pop 4 bytes / eflags) + */ + ptr[i * 6 + 0] = 0xCD; + ptr[i * 6 + 1] = i; + ptr[i * 6 + 2] = 0x66; + ptr[i * 6 + 3] = 0xCA; + ptr[i * 6 + 4] = 0x04; + ptr[i * 6 + 5] = 0x00; + } + + /* + * PM / offset N*5: Interrupt N in 16-bit protected mode. + */ + ptr = DOSVM_AllocCodeUMB( 5 * 256, + 0, &DOSVM_dpmi_segments->int16_sel ); + for(i=0; i<256; i++) { + /* + * Each 16-bit interrupt handler is 5 bytes: + * 0xCD, = int (interrupt) + * 0xCA,0x02,0x00 = ret 2 (16-bit far return and pop 2 bytes / eflags) + */ + ptr[i * 5 + 0] = 0xCD; + ptr[i * 5 + 1] = i; + ptr[i * 5 + 2] = 0xCA; + ptr[i * 5 + 3] = 0x02; + ptr[i * 5 + 4] = 0x00; + } + + /* + * PM / offset 0: Stub where __wine_call_from_16_regs returns. + * PM / offset 3: Stub which swaps back to 32-bit application code/stack. + * PM / offset 5: Stub which enables interrupts + */ + ptr = DOSVM_AllocCodeUMB( sizeof(relay), + 0, &DOSVM_dpmi_segments->relay_code_sel); + memcpy( ptr, relay, sizeof(relay) ); + + /* + * Space for 16-bit stack used by relay code. + */ + ptr = DOSVM_AllocDataUMB( DOSVM_RELAY_DATA_SIZE, + 0, &DOSVM_dpmi_segments->relay_data_sel); + memset( ptr, 0, DOSVM_RELAY_DATA_SIZE ); + + /* + * As we store code in UMB we should make sure it is executable + */ + VirtualProtect((void *)DOSVM_UMB_BOTTOM, DOSVM_UMB_TOP - DOSVM_UMB_BOTTOM, PAGE_EXECUTE_READWRITE, NULL); +} + + /********************************************************************** * DllMain (DOSVM.0) */ diff --git a/dlls/winedos/himem.c b/dlls/winedos/himem.c deleted file mode 100644 index a7d6099eb59..00000000000 --- a/dlls/winedos/himem.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * DOS upper memory management. - * - * Copyright 2002 Jukka Heinonen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "dosexe.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dosmem); - -/* - * Wine DOS memory layout above 640k: - * - * a0000 - affff : VGA graphics (vga.c) - * b0000 - bffff : Monochrome text (unused) - * b8000 - bffff : VGA text (vga.c) - * c0000 - cffff : EMS frame (int67.c) - * d0000 - effff : Free memory for UMBs (himem.c) - * f0000 - fffff : BIOS stuff (msdos/dosmem.c) - * 100000 -10ffff : High memory area (unused) - */ - -/* - * Table of real mode segments and protected mode selectors - * for code stubs and other miscellaneous storage. - */ -struct DPMI_segments *DOSVM_dpmi_segments = NULL; - -/* - * First and last address available for upper memory blocks. - */ -#define DOSVM_UMB_BOTTOM 0xd0000 -#define DOSVM_UMB_TOP 0xeffff - -/* - * First free address for upper memory blocks. - */ -static DWORD DOSVM_umb_free = DOSVM_UMB_BOTTOM; - - -/*********************************************************************** - * DOSVM_AllocUMB - * - * Allocate upper memory block (UMB) from upper memory. - * Returned pointer is aligned to 16-byte (paragraph) boundary. - * - * This routine is only for allocating static storage for - * Wine internal uses. Allocated memory can be accessed from - * real mode, memory is taken from area already mapped and reserved - * by Wine and the allocation has very little memory and speed - * overhead. Use of this routine also preserves precious DOS - * conventional memory. - */ -static LPVOID DOSVM_AllocUMB( DWORD size ) -{ - LPVOID ptr = (LPVOID)DOSVM_umb_free; - - size = ((size + 15) >> 4) << 4; - - if(DOSVM_umb_free + size - 1 > DOSVM_UMB_TOP) { - ERR("Out of upper memory area.\n"); - return 0; - } - - DOSVM_umb_free += size; - return ptr; -} - - -/********************************************************************** - * alloc_selector - * - * Allocate a selector corresponding to a real mode address. - * size must be < 64k. - */ -static WORD alloc_selector( void *base, DWORD size, unsigned char flags ) -{ - WORD sel = wine_ldt_alloc_entries( 1 ); - - if (sel) - { - LDT_ENTRY entry; - wine_ldt_set_base( &entry, base ); - wine_ldt_set_limit( &entry, size - 1 ); - wine_ldt_set_flags( &entry, flags ); - wine_ldt_set_entry( sel, &entry ); - } - return sel; -} - - -/*********************************************************************** - * DOSVM_AllocCodeUMB - * - * Allocate upper memory block for storing code stubs. - * Initializes real mode segment and 16-bit protected mode selector - * for the allocated code block. - * - * FIXME: should allocate a single PM selector for the whole UMB range. - */ -static LPVOID DOSVM_AllocCodeUMB( DWORD size, WORD *segment, WORD *selector ) -{ - LPVOID ptr = DOSVM_AllocUMB( size ); - - if (segment) - *segment = (DWORD)ptr >> 4; - - if (selector) - *selector = alloc_selector( ptr, size, WINE_LDT_FLAGS_CODE ); - - return ptr; -} - - -/*********************************************************************** - * DOSVM_AllocDataUMB - * - * Allocate upper memory block for storing data. - * Initializes real mode segment and 16-bit protected mode selector - * for the allocated data block. - */ -LPVOID DOSVM_AllocDataUMB( DWORD size, WORD *segment, WORD *selector ) -{ - LPVOID ptr = DOSVM_AllocUMB( size ); - - if (segment) - *segment = (DWORD)ptr >> 4; - - if (selector) - *selector = alloc_selector( ptr, size, WINE_LDT_FLAGS_DATA ); - - return ptr; -} - - -/*********************************************************************** - * DOSVM_InitSegments - * - * Initializes DOSVM_dpmi_segments. Allocates required memory and - * sets up segments and selectors for accessing the memory. - */ -void DOSVM_InitSegments( void ) -{ - LPSTR ptr; - int i; - - static const char wrap_code[]={ - 0xCD,0x31, /* int $0x31 */ - 0xCB /* lret */ - }; - - static const char enter_xms[]= - { - /* XMS hookable entry point */ - 0xEB,0x03, /* jmp entry */ - 0x90,0x90,0x90, /* nop;nop;nop */ - /* entry: */ - /* real entry point */ - /* for simplicity, we'll just use the same hook as DPMI below */ - 0xCD,0x31, /* int $0x31 */ - 0xCB /* lret */ - }; - - static const char enter_pm[]= - { - 0x50, /* pushw %ax */ - 0x52, /* pushw %dx */ - 0x55, /* pushw %bp */ - 0x89,0xE5, /* movw %sp,%bp */ - /* get return CS */ - 0x8B,0x56,0x08, /* movw 8(%bp),%dx */ - /* just call int 31 here to get into protected mode... */ - /* it'll check whether it was called from dpmi_seg... */ - 0xCD,0x31, /* int $0x31 */ - /* we are now in the context of a 16-bit relay call */ - /* need to fixup our stack; - * 16-bit relay return address will be lost, - * but we won't worry quite yet - */ - 0x8E,0xD0, /* movw %ax,%ss */ - 0x66,0x0F,0xB7,0xE5, /* movzwl %bp,%esp */ - /* set return CS */ - 0x89,0x56,0x08, /* movw %dx,8(%bp) */ - 0x5D, /* popw %bp */ - 0x5A, /* popw %dx */ - 0x58, /* popw %ax */ - 0xfb, /* sti, enable and check virtual interrupts */ - 0xCB /* lret */ - }; - - static const char relay[]= - { - 0xca, 0x04, 0x00, /* 16-bit far return and pop 4 bytes (relay void* arg) */ - 0xcd, 0x31, /* int 31 */ - 0xfb, 0x66, 0xcb /* sti and 32-bit far return */ - }; - - /* - * Allocate pointer array. - */ - DOSVM_dpmi_segments = DOSVM_AllocUMB( sizeof(struct DPMI_segments) ); - - /* - * RM / offset 0: Exit from real mode. - * RM / offset 2: Points to lret opcode. - */ - ptr = DOSVM_AllocCodeUMB( sizeof(wrap_code), - &DOSVM_dpmi_segments->wrap_seg, 0 ); - memcpy( ptr, wrap_code, sizeof(wrap_code) ); - - /* - * RM / offset 0: XMS driver entry. - */ - ptr = DOSVM_AllocCodeUMB( sizeof(enter_xms), - &DOSVM_dpmi_segments->xms_seg, 0 ); - memcpy( ptr, enter_xms, sizeof(enter_xms) ); - - /* - * RM / offset 0: Switch to DPMI. - * PM / offset 8: DPMI raw mode switch. - */ - ptr = DOSVM_AllocCodeUMB( sizeof(enter_pm), - &DOSVM_dpmi_segments->dpmi_seg, - &DOSVM_dpmi_segments->dpmi_sel ); - memcpy( ptr, enter_pm, sizeof(enter_pm) ); - - /* - * PM / offset N*6: Interrupt N in DPMI32. - */ - ptr = DOSVM_AllocCodeUMB( 6 * 256, - 0, &DOSVM_dpmi_segments->int48_sel ); - for(i=0; i<256; i++) { - /* - * Each 32-bit interrupt handler is 6 bytes: - * 0xCD, = int (nested 16-bit interrupt) - * 0x66,0xCA,0x04,0x00 = ret 4 (32-bit far return and pop 4 bytes / eflags) - */ - ptr[i * 6 + 0] = 0xCD; - ptr[i * 6 + 1] = i; - ptr[i * 6 + 2] = 0x66; - ptr[i * 6 + 3] = 0xCA; - ptr[i * 6 + 4] = 0x04; - ptr[i * 6 + 5] = 0x00; - } - - /* - * PM / offset N*5: Interrupt N in 16-bit protected mode. - */ - ptr = DOSVM_AllocCodeUMB( 5 * 256, - 0, &DOSVM_dpmi_segments->int16_sel ); - for(i=0; i<256; i++) { - /* - * Each 16-bit interrupt handler is 5 bytes: - * 0xCD, = int (interrupt) - * 0xCA,0x02,0x00 = ret 2 (16-bit far return and pop 2 bytes / eflags) - */ - ptr[i * 5 + 0] = 0xCD; - ptr[i * 5 + 1] = i; - ptr[i * 5 + 2] = 0xCA; - ptr[i * 5 + 3] = 0x02; - ptr[i * 5 + 4] = 0x00; - } - - /* - * PM / offset 0: Stub where __wine_call_from_16_regs returns. - * PM / offset 3: Stub which swaps back to 32-bit application code/stack. - * PM / offset 5: Stub which enables interrupts - */ - ptr = DOSVM_AllocCodeUMB( sizeof(relay), - 0, &DOSVM_dpmi_segments->relay_code_sel); - memcpy( ptr, relay, sizeof(relay) ); - - /* - * Space for 16-bit stack used by relay code. - */ - ptr = DOSVM_AllocDataUMB( DOSVM_RELAY_DATA_SIZE, - 0, &DOSVM_dpmi_segments->relay_data_sel); - memset( ptr, 0, DOSVM_RELAY_DATA_SIZE ); - - /* - * As we store code in UMB we should make sure it is executable - */ - VirtualProtect((void *)DOSVM_UMB_BOTTOM, DOSVM_UMB_TOP - DOSVM_UMB_BOTTOM, PAGE_EXECUTE_READWRITE, NULL); -}