From fd33517a4121d7fcb48b49b2d6ab2c10af468d8a Mon Sep 17 00:00:00 2001 From: Jukka Heinonen Date: Tue, 29 Jan 2002 17:55:21 +0000 Subject: [PATCH] Added support for DOS EMS memory. --- dlls/winedos/Makefile.in | 1 + dlls/winedos/dosexe.h | 4 + dlls/winedos/dosvm.c | 8 +- dlls/winedos/int21.c | 49 ++++-- dlls/winedos/int67.c | 355 +++++++++++++++++++++++++++++++++++++++ files/dos_fs.c | 6 +- 6 files changed, 403 insertions(+), 20 deletions(-) create mode 100644 dlls/winedos/int67.c diff --git a/dlls/winedos/Makefile.in b/dlls/winedos/Makefile.in index 16f3134522..a86c1fbba6 100644 --- a/dlls/winedos/Makefile.in +++ b/dlls/winedos/Makefile.in @@ -21,6 +21,7 @@ C_SRCS = \ int29.c \ int31.c \ int33.c \ + int67.c \ ioports.c \ module.c \ vga.c \ diff --git a/dlls/winedos/dosexe.h b/dlls/winedos/dosexe.h index 60fbd01a6d..1853534cc9 100644 --- a/dlls/winedos/dosexe.h +++ b/dlls/winedos/dosexe.h @@ -92,6 +92,10 @@ extern void WINAPI DOSVM_Int31Handler(CONTEXT86*); extern void WINAPI DOSVM_Int33Handler(CONTEXT86*); extern void WINAPI DOSVM_Int33Message(UINT,WPARAM,LPARAM); +/* int67.c */ +extern void WINAPI DOSVM_Int67Handler(CONTEXT86*); +extern void WINAPI EMS_Ioctl_Handler(CONTEXT86*); + /* xms.c */ extern void WINAPI XMS_Handler(CONTEXT86*); diff --git a/dlls/winedos/dosvm.c b/dlls/winedos/dosvm.c index a8a439c492..962b718050 100644 --- a/dlls/winedos/dosvm.c +++ b/dlls/winedos/dosvm.c @@ -603,7 +603,13 @@ static const INTPROC real_mode_handlers[] = /* 18 */ 0, 0, INT_Int1aHandler, 0, 0, 0, 0, 0, /* 20 */ DOSVM_Int20Handler, DOSVM_Int21Handler, 0, 0, 0, INT_Int25Handler, 0, 0, /* 28 */ 0, DOSVM_Int29Handler, INT_Int2aHandler, 0, 0, 0, 0, INT_Int2fHandler, - /* 30 */ 0, DOSVM_Int31Handler, 0, DOSVM_Int33Handler + /* 30 */ 0, DOSVM_Int31Handler, 0, DOSVM_Int33Handler, 0, 0, 0, 0, + /* 38 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 40 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 48 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 58 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 60 */ 0, 0, 0, 0, 0, 0, 0, DOSVM_Int67Handler }; diff --git a/dlls/winedos/int21.c b/dlls/winedos/int21.c index e0dfda473f..2a39f8ad52 100644 --- a/dlls/winedos/int21.c +++ b/dlls/winedos/int21.c @@ -12,10 +12,41 @@ #include "miscemu.h" #include "msdos.h" #include "console.h" +#include "file.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(int21); +void WINAPI DOSVM_Int21Handler_Ioctl( CONTEXT86 *context ) +{ + const DOS_DEVICE *dev = DOSFS_GetDeviceByHandle( + DosFileHandleToWin32Handle(BX_reg(context)) ); + + if (dev && !strcasecmp( dev->name, "EMMXXXX0" )) { + EMS_Ioctl_Handler(context); + return; + } + + switch (AL_reg(context)) + { + case 0x0b: /* SET SHARING RETRY COUNT */ + TRACE("IOCTL - SET SHARING RETRY COUNT pause %d retries %d\n", + CX_reg(context), DX_reg(context)); + if (!CX_reg(context)) + { + AX_reg(context) = 1; + SET_CFLAG(context); + break; + } + DOSMEM_LOL()->sharing_retry_delay = CX_reg(context); + if (!DX_reg(context)) + DOSMEM_LOL()->sharing_retry_count = DX_reg(context); + RESET_CFLAG(context); + break; + default: + DOS3Call( context ); + } +} /*********************************************************************** * DOSVM_Int21Handler @@ -114,23 +145,7 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) break; case 0x44: /* IOCTL */ - switch (AL_reg(context)) - { - case 0x0b: /* SET SHARING RETRY COUNT */ - TRACE("IOCTL - SET SHARING RETRY COUNT pause %d retries %d\n", - CX_reg(context), DX_reg(context)); - if (!CX_reg(context)) - { - AX_reg(context) = 1; - SET_CFLAG(context); - break; - } - DOSMEM_LOL()->sharing_retry_delay = CX_reg(context); - if (!DX_reg(context)) - DOSMEM_LOL()->sharing_retry_count = DX_reg(context); - RESET_CFLAG(context); - break; - } + DOSVM_Int21Handler_Ioctl( context ); break; case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */ diff --git a/dlls/winedos/int67.c b/dlls/winedos/int67.c new file mode 100644 index 0000000000..11abe9ddaa --- /dev/null +++ b/dlls/winedos/int67.c @@ -0,0 +1,355 @@ +/* + * Int67 (EMS) emulation + */ + +#include +#include "wine/winbase16.h" +#include "dosexe.h" +#include "miscemu.h" +#include "debugtools.h" + +DEFAULT_DEBUG_CHANNEL(int); + +/* + * EMS page size == 16 kilobytes. + */ +#define EMS_PAGE_SIZE (16*1024) + +/* + * Linear address of EMS page. + */ +#define EMS_PAGE_ADDRESS(base,page) (((char*)base) + EMS_PAGE_SIZE * page) + +/* + * Maximum number of pages that can be allocated using EMS. + */ +#define EMS_MAX_PAGES 1024 + +/* + * Maximum number of EMS handles (allocated blocks). + */ +#define EMS_MAX_HANDLES 256 + +/* + * Global EMM Import Record. + * Applications can get address of this record + * and directly access allocated memory if they use + * IOCTL interface. + * + * FIXME: Missing lots of fields, packing is not correct. + */ + +struct { + struct { + UCHAR hindex; /* handle number */ + BYTE flags; /* bit 0: normal handle rather than system handle */ + char name[8]; /* handle name */ + WORD pages; /* allocated pages */ + void *address; /* physical address*/ + } handle[EMS_MAX_HANDLES]; + + /* Wine specific fields... */ + + int used_pages; /* Number of allocated pages. */ + void *frame_address; /* Address of 64k EMS page frame */ + WORD frame_selector; /* Segment of 64k EMS page frame */ + + struct { + UCHAR hindex; /* handle number */ + WORD logical_page; /* logical page */ + } mapping[4]; + +} *EMS_record = 0; + +/********************************************************************** + * EMS_init + * + * Allocates and initialized page frame and EMS global import record. + */ +static void EMS_init(void) +{ + /* + * FIXME: Should dynamically allocate upper memory block for EMS frame. + */ + ULONG base = 0xd0000; + + if(EMS_record) + return; + + EMS_record = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(*EMS_record)); + + EMS_record->frame_address = DOSMEM_MapDosToLinear(base); + EMS_record->frame_selector = base >> 4; +} + +/********************************************************************** + * EMS_alloc + * + * Get handle and allocate memory. + */ +static void EMS_alloc( CONTEXT86 *context ) +{ + int hindex = 1; /* handle zero is reserved for system */ + + while(hindex < EMS_MAX_HANDLES && EMS_record->handle[hindex].address) + hindex++; + + if(hindex == EMS_MAX_HANDLES) { + AH_reg(context) = 0x85; /* status: no more handles available */ + } else { + int pages = BX_reg(context); + void *buffer = HeapAlloc( GetProcessHeap(), 0, pages * EMS_PAGE_SIZE ); + + if(!buffer) { + AH_reg(context) = 0x88; /* status: insufficient pages available */ + } else { + EMS_record->handle[hindex].address = buffer; + EMS_record->handle[hindex].pages = pages; + EMS_record->used_pages += pages; + + DX_reg(context) = hindex; /* handle to allocated memory*/ + AH_reg(context) = 0; /* status: ok */ + } + } +} + +/********************************************************************** + * EMS_access_name + * + * Get/set handle name. + */ +static void EMS_access_name( CONTEXT86 *context ) +{ + char *ptr; + int hindex = DX_reg(context); + if(hindex < 0 || hindex >= EMS_MAX_HANDLES) { + AH_reg(context) = 0x83; /* invalid handle */ + return; + } + + switch AL_reg(context) { + case 0x00: /* get name */ + ptr = MapSL(MAKESEGPTR(context->SegEs, DI_reg(context))); + memcpy(ptr, EMS_record->handle[hindex].name, 8); + AH_reg(context) = 0; + break; + + case 0x01: /* set name */ + ptr = MapSL(MAKESEGPTR(context->SegDs, SI_reg(context))); + memcpy(EMS_record->handle[hindex].name, ptr, 8); + AH_reg(context) = 0; + break; + + default: + INT_BARF(context,0x67); + break; + } +} + +/********************************************************************** + * EMS_map + * + * Map logical page into physical page. + */ +static void EMS_map( CONTEXT86 *context ) +{ + int physical_page = AL_reg(context); + int new_hindex = DX_reg(context); + int new_logical_page = BX_reg(context); + + int old_hindex = EMS_record->mapping[physical_page].hindex; + int old_logical_page = EMS_record->mapping[physical_page].logical_page; + + void *physical_address = EMS_PAGE_ADDRESS(EMS_record->frame_address, + physical_page); + + /* unmap old page */ + if(old_hindex) { + void *ptr = EMS_PAGE_ADDRESS(EMS_record->handle[old_hindex].address, + old_logical_page); + memcpy(ptr, physical_address, EMS_PAGE_SIZE); + } + + /* map new page */ + if(new_hindex && new_logical_page != 0xffff) { + void *ptr = EMS_PAGE_ADDRESS(EMS_record->handle[new_hindex].address, + new_logical_page); + memcpy(physical_address, ptr, EMS_PAGE_SIZE); + EMS_record->mapping[physical_page].hindex = new_hindex; + EMS_record->mapping[physical_page].logical_page = new_logical_page; + } else { + EMS_record->mapping[physical_page].hindex = 0; + EMS_record->mapping[physical_page].logical_page = 0; + } + + AH_reg(context) = 0; /* status: ok */ +} + +/********************************************************************** + * EMS_free + * + * Free memory and release handle. + */ +static void EMS_free( CONTEXT86 *context ) +{ + int hindex = DX_reg(context); + int i; + + if(hindex < 0 || hindex >= EMS_MAX_HANDLES) { + AH_reg(context) = 0x83; /* status: invalid handle */ + return; + } + + if(!EMS_record->handle[hindex].address) { + AH_reg(context) = 0; /* status: ok */ + return; + } + + EMS_record->used_pages -= EMS_record->handle[hindex].pages; + + /* unmap pages */ + for(i=0; i<4; i++) + if(EMS_record->mapping[i].hindex == hindex) + EMS_record->mapping[i].hindex = 0; + + /* free block */ + HeapFree( GetProcessHeap(), 0, EMS_record->handle[hindex].address ); + EMS_record->handle[hindex].address = 0; + + AH_reg(context) = 0; /* status: ok */ +} + +/********************************************************************** + * DOSVM_Int67Handler + * + * Handler for interrupt 67h EMS routines. + */ +void WINAPI DOSVM_Int67Handler( CONTEXT86 *context ) +{ + switch AH_reg(context) { + + case 0x40: /* EMS - GET MANAGER STATUS */ + AH_reg(context) = 0; /* status: ok */ + break; + + case 0x41: /* EMS - GET PAGE FRAME SEGMENT */ + EMS_init(); + BX_reg(context) = EMS_record->frame_selector; /* segment of page frame */ + AH_reg(context) = 0; /* status: ok */ + break; + + case 0x42: /* EMS - GET NUMBER OF PAGES */ + EMS_init(); + /* unallocated 16k pages */ + BX_reg(context) = EMS_MAX_PAGES - EMS_record->used_pages; + /* total number of 16k pages */ + DX_reg(context) = EMS_MAX_PAGES; + /* status: ok */ + AH_reg(context) = 0; + break; + + case 0x43: /* EMS - GET HANDLE AND ALLOCATE MEMORY */ + EMS_init(); + EMS_alloc(context); + break; + + case 0x44: /* EMS - MAP MEMORY */ + EMS_init(); + EMS_map(context); + break; + + case 0x45: /* EMS - RELEASE HANDLE AND MEMORY */ + EMS_init(); + EMS_free(context); + break; + + case 0x46: /* EMS - GET EMM VERSION */ + AL_reg(context) = 0x40; /* version 4.0 */ + AH_reg(context) = 0; /* status: ok */ + break; + + case 0x47: /* EMS - SAVE MAPPING CONTEXT */ + case 0x48: /* EMS - RESTORE MAPPING CONTEXT */ + INT_BARF(context,0x67); + break; + + case 0x49: /* EMS - reserved - GET I/O PORT ADDRESSES */ + case 0x4a: /* EMS - reserved - GET TRANSLATION ARRAY */ + INT_BARF(context,0x67); + break; + + case 0x4b: /* EMS - GET NUMBER OF EMM HANDLES */ + BX_reg(context) = EMS_MAX_HANDLES; /* EMM handles */ + AH_reg(context) = 0; /* status: ok */ + break; + + case 0x4c: /* EMS - GET PAGES OWNED BY HANDLE */ + case 0x4d: /* EMS - GET PAGES FOR ALL HANDLES */ + case 0x4e: /* EMS - GET OR SET PAGE MAP */ + case 0x4f: /* EMS 4.0 - GET/SET PARTIAL PAGE MAP */ + case 0x50: /* EMS 4.0 - MAP/UNMAP MULTIPLE HANDLE PAGES */ + case 0x51: /* EMS 4.0 - REALLOCATE PAGES */ + case 0x52: /* EMS 4.0 - GET/SET HANDLE ATTRIBUTES */ + INT_BARF(context,0x67); + break; + + case 0x53: /* EMS 4.0 - GET/SET HANDLE NAME */ + EMS_init(); + EMS_access_name(context); + break; + + case 0x54: /* EMS 4.0 - GET HANDLE DIRECTORY */ + case 0x55: /* EMS 4.0 - ALTER PAGE MAP AND JUMP */ + case 0x56: /* EMS 4.0 - ALTER PAGE MAP AND CALL */ + case 0x57: /* EMS 4.0 - MOVE/EXCHANGE MEMORY REGION */ + case 0x58: /* EMS 4.0 - GET MAPPABLE PHYSICAL ADDRESS ARRAY */ + case 0x59: /* EMS 4.0 - GET EXPANDED MEMORY HARDWARE INFORMATION */ + case 0x5a: /* EMS 4.0 - ALLOCATE STANDARD/RAW PAGES */ + case 0x5b: /* EMS 4.0 - ALTERNATE MAP REGISTER SET */ + case 0x5c: /* EMS 4.0 - PREPARE EXPANDED MEMORY HARDWARE FOR WARM BOOT */ + case 0x5d: /* EMS 4.0 - ENABLE/DISABLE OS FUNCTION SET FUNCTIONS */ + default: + INT_BARF(context,0x67); + } +} + + +/********************************************************************** + * EMS_Ioctl_Handler + * + * Handler for interrupt 21h IOCTL routine for device "EMMXXXX0". + */ +void WINAPI EMS_Ioctl_Handler( CONTEXT86 *context ) +{ + assert(AH_reg(context) == 0x44); + + switch AL_reg(context) { + case 0x00: /* IOCTL - GET DEVICE INFORMATION */ + RESET_CFLAG(context); /* operation was successful */ + DX_reg(context) = 0x4080; /* bit 14 (support ioctl read) and + * bit 7 (is_device) */ + break; + + case 0x02: /* EMS - GET MEMORY MANAGER INFORMATION */ + /* + * This is what is called "Windows Global EMM Import Specification". + * Undocumented of course! Supports three requests: + * GET API ENTRY POINT + * GET EMM IMPORT STRUCTURE ADDRESS + * GET MEMORY MANAGER VERSION + */ + INT_BARF(context,0x21); + break; + + case 0x07: /* IOCTL - GET OUTPUT STATUS */ + RESET_CFLAG(context); /* operation was successful */ + AL_reg(context) = 0xff; /* device is ready */ + break; + + default: + INT_BARF(context,0x21); + break; + } +} diff --git a/files/dos_fs.c b/files/dos_fs.c index d62cc92650..f3f3aae0d8 100644 --- a/files/dos_fs.c +++ b/files/dos_fs.c @@ -78,7 +78,8 @@ static const DOS_DEVICE DOSFS_Devices[] = { "COM3", 0x80c0 }, { "COM4", 0x80c0 }, { "SCSIMGR$", 0xc0c0 }, - { "HPSCAN", 0xc0c0 } + { "HPSCAN", 0xc0c0 }, + { "EMMXXXX0", 0x0000 } }; #define GET_DRIVE(path) \ @@ -786,7 +787,8 @@ HANDLE DOSFS_OpenDevice( const char *name, DWORD access, DWORD attributes, LPSEC return handle; } if (!strcmp(DOSFS_Devices[i].name,"SCSIMGR$") || - !strcmp(DOSFS_Devices[i].name,"HPSCAN")) + !strcmp(DOSFS_Devices[i].name,"HPSCAN") || + !strcmp(DOSFS_Devices[i].name,"EMMXXXX0")) { return FILE_CreateDevice( i, access, sa ); } -- 2.32.0.93.g670b81a890