From caff0f7a8b5bb0ae2a82d3fc2f8cf11a07e89274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Strohh=C3=A4cker?= Date: Mon, 8 Aug 2005 13:33:46 +0000 Subject: [PATCH] adding support for upper memory Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@2262 --- include/callback.h | 4 +- include/dos_inc.h | 28 +++++--- src/dos/dos.cpp | 13 ++-- src/dos/dos_classes.cpp | 36 ++++++++-- src/dos/dos_memory.cpp | 146 +++++++++++++++++++++++++++++++++++++-- src/dos/dos_programs.cpp | 34 ++++++++- src/dos/dos_tables.cpp | 11 +-- src/dosbox.cpp | 4 +- src/ints/xms.cpp | 76 ++++++++++++++++++-- 9 files changed, 304 insertions(+), 48 deletions(-) diff --git a/include/callback.h b/include/callback.h index 5a6a5c0e..a6603387 100644 --- a/include/callback.h +++ b/include/callback.h @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: callback.h,v 1.13 2005-07-30 09:49:28 qbix79 Exp $ */ +/* $Id: callback.h,v 1.14 2005-08-08 13:33:43 c2woody Exp $ */ #ifndef DOSBOX_CALLBACK_H #define DOSBOX_CALLBACK_H @@ -30,7 +30,7 @@ extern CallBack_Handler CallBack_Handlers[]; enum { CB_RETF,CB_IRET,CB_IRET_STI }; -#define CB_MAX 1024 +#define CB_MAX 144 #define CB_SEG 0xC800 #define CB_BASE (CB_SEG << 4) diff --git a/include/dos_inc.h b/include/dos_inc.h index 1e27f92e..a68f81df 100644 --- a/include/dos_inc.h +++ b/include/dos_inc.h @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_inc.h,v 1.54 2005-08-01 09:30:44 c2woody Exp $ */ +/* $Id: dos_inc.h,v 1.55 2005-08-08 13:33:43 c2woody Exp $ */ #ifndef DOSBOX_DOS_INC_H #define DOSBOX_DOS_INC_H @@ -76,13 +76,13 @@ enum { RETURN_EXIT=0,RETURN_CTRLC=1,RETURN_ABORT=2,RETURN_TSR=3}; #define DOS_DRIVES 26 #define DOS_DEVICES 10 -#define DOS_INFOBLOCK_SEG 0x50 -#define DOS_SDA_SEG 0x5a + +#define DOS_INFOBLOCK_SEG 0x80 +#define DOS_CDS_SEG 0x90 +#define DOS_CONSTRING_SEG 0xa0 +#define DOS_CONDRV_SEG 0xa4 +#define DOS_SDA_SEG 0xb0 #define DOS_SDA_OFS 0 -#define DOS_CONSTRING_SEG 0x5d -#define DOS_CONDRV_SEG 0x60 -#define DOS_SFT_SEG 0x62 -#define DOS_CDS_SEG 0x64 #define DOS_MEM_START 0x102 //First Segment that DOS can use /* internal Dos Tables */ @@ -158,6 +158,8 @@ void DOS_FreeProcessMemory(Bit16u pspseg); Bit16u DOS_GetMemory(Bit16u pages); void DOS_SetMemAllocStrategy(Bit16u strat); Bit16u DOS_GetMemAllocStrategy(void); +void DOS_BuildUMBChain(const char* use_umbs,bool ems_active); +bool DOS_LinkUMBsToMemChain(Bit16u linkstate); /* FCB stuff */ bool DOS_FCBOpen(Bit16u seg,Bit16u offset); @@ -354,18 +356,24 @@ public: DOS_InfoBlock () {}; void SetLocation(Bit16u seg); void SetFirstMCB(Bit16u _first_mcb); - void SetfirstFileTable(RealPt _first_table); void SetBuffers(Bit16u x,Bit16u y); void SetCurDirStruct(Bit32u _curdirstruct); void SetFCBTable(Bit32u _fcbtable); void SetDeviceChainStart(Bit32u _devchain); void SetDiskBufferHeadPt(Bit32u _dbheadpt); - RealPt GetPointer (void); + void SetStartOfUMBChain(Bit16u _umbstartseg); + void SetUMBChainState(Bit8u _umbchaining); + Bit16u GetStartOfUMBChain(void); + Bit8u GetUMBChainState(void); + RealPt GetPointer(void); #ifdef _MSC_VER #pragma pack(1) #endif struct sDIB { + Bit8u unknown1[4]; + Bit16u magicWord; // -0x22 needs to be 1 + Bit8u unknown2[8]; Bit16u regCXfrom5e; // -0x18 CX from last int21/ah=5e Bit16u countLRUcache; // -0x16 LRU counter for FCB caching Bit16u countLRUopens; // -0x14 LRU counter for FCB openings @@ -406,7 +414,7 @@ public: Bit16u lookaheadBufNumber; // 0x51 number of lookahead buffers Bit8u bufferLocation; // 0x53 workspace buffer location Bit32u workspaceBuffer; // 0x54 pointer to workspace buffer - Bit8u unknown2[11]; // 0x58 + Bit8u unknown3[11]; // 0x58 Bit8u chainingUMB; // 0x63 bit0: UMB chain linked to MCB chain Bit16u minMemForExec; // 0x64 minimum paragraphs needed for current program Bit16u startOfUMBChain; // 0x66 segment of first UMB-MCB diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index 2b365d88..9ab3f757 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos.cpp,v 1.84 2005-04-29 13:32:31 qbix79 Exp $ */ +/* $Id: dos.cpp,v 1.85 2005-08-08 13:33:44 c2woody Exp $ */ #include #include @@ -716,12 +716,15 @@ static Bitu DOS_21Handler(void) { DOS_SetMemAllocStrategy(reg_bx); break; case 2: /* Get UMB Link Status */ - reg_ax=1; // no UMB support - CALLBACK_SCF(true); + reg_al=dos_infoblock.GetUMBChainState()&1; + CALLBACK_SCF(false); break; case 3: /* Set UMB Link Status */ - reg_ax=1; // failure, no support - CALLBACK_SCF(true); + if (DOS_LinkUMBsToMemChain(reg_bx)) CALLBACK_SCF(false); + else { + reg_ax=1; + CALLBACK_SCF(true); + } break; default: LOG(LOG_DOSMISC,LOG_ERROR)("DOS:58:Not Supported Set//Get memory allocation call %X",reg_al); diff --git a/src/dos/dos_classes.cpp b/src/dos/dos_classes.cpp index dfdafe60..17411c3f 100644 --- a/src/dos/dos_classes.cpp +++ b/src/dos/dos_classes.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_classes.cpp,v 1.44 2005-08-01 09:30:45 c2woody Exp $ */ +/* $Id: dos_classes.cpp,v 1.45 2005-08-08 13:33:45 c2woody Exp $ */ #include #include @@ -63,6 +63,7 @@ void DOS_InfoBlock::SetLocation(Bit16u segment) { pt=PhysMake(seg,0); /* Clear the initial Block */ for(Bitu i=0;i16mb + sSave(sDIB,magicWord,(Bit16u)0x0001); // dos5+ sSave(sDIB,sharingCount,(Bit16u)0); sSave(sDIB,sharingDelay,(Bit16u)0); + sSave(sDIB,ptrCONinput,(Bit16u)0); // no unread input available + sSave(sDIB,maxSectorLength,(Bit16u)0x200); sSave(sDIB,dirtyDiskBuffers,(Bit16u)0); sSave(sDIB,lookaheadBufPt,(Bit32u)0); @@ -109,16 +113,20 @@ void DOS_InfoBlock::SetLocation(Bit16u segment) { sSave(sDIB,nulString[5],(Bit8u)0x20); sSave(sDIB,nulString[6],(Bit8u)0x20); sSave(sDIB,nulString[7],(Bit8u)0x20); + + /* Create a fake SFT, so programs think there are 100 file handles */ + Bit16u sftOffset=offsetof(sDIB,firstFileTable)+0xa2; + sSave(sDIB,firstFileTable,RealMake(segment,sftOffset)); + real_writed(segment,sftOffset+0x00,RealMake(segment+0x11,0)); //Next File Table + real_writew(segment,sftOffset+0x04,100); //File Table supports 100 files + real_writed(segment+0x11,0x00,0xffffffff); //Last File Table + real_writew(segment+0x11,0x04,100); //File Table supports 100 files } void DOS_InfoBlock::SetFirstMCB(Bit16u _firstmcb) { sSave(sDIB,firstMCB,_firstmcb); //c2woody } -void DOS_InfoBlock::SetfirstFileTable(RealPt _first_table) { - sSave(sDIB,firstFileTable,_first_table); -} - void DOS_InfoBlock::SetBuffers(Bit16u x,Bit16u y) { sSave(sDIB,buffers_x,x); sSave(sDIB,buffers_y,y); @@ -140,6 +148,22 @@ void DOS_InfoBlock::SetDiskBufferHeadPt(Bit32u _dbheadpt) { sSave(sDIB,diskBufferHeadPt,_dbheadpt); } +Bit16u DOS_InfoBlock::GetStartOfUMBChain(void) { + return sGet(sDIB,startOfUMBChain); +} + +void DOS_InfoBlock::SetStartOfUMBChain(Bit16u _umbstartseg) { + sSave(sDIB,startOfUMBChain,_umbstartseg); +} + +Bit8u DOS_InfoBlock::GetUMBChainState(void) { + return sGet(sDIB,chainingUMB); +} + +void DOS_InfoBlock::SetUMBChainState(Bit8u _umbchaining) { + sSave(sDIB,chainingUMB,_umbchaining); +} + RealPt DOS_InfoBlock::GetPointer(void) { return RealMake(seg,offsetof(sDIB,firstDPB)); } diff --git a/src/dos/dos_memory.cpp b/src/dos/dos_memory.cpp index df0ec862..1558f013 100644 --- a/src/dos/dos_memory.cpp +++ b/src/dos/dos_memory.cpp @@ -20,6 +20,8 @@ #include "mem.h" #include "dos_inc.h" +#define UMB_START_SEG 0x9fff + static Bit16u memAllocStrategy = 0x00; static void DOS_CompressMemory(void) { @@ -50,6 +52,20 @@ void DOS_FreeProcessMemory(Bit16u pspseg) { mcb_segment+=mcb.GetSize()+1; mcb.SetPt(mcb_segment); } + + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + if (umb_start==UMB_START_SEG) { + DOS_MCB umb_mcb(umb_start); + while (true) { + if (umb_mcb.GetPSPSeg()==pspseg) { + umb_mcb.SetPSPSeg(MCB_FREE); + } + if (umb_mcb.GetType()!=0x4d) break; + umb_start+=umb_mcb.GetSize()+1; + umb_mcb.SetPt(umb_start); + } + } else if (umb_start!=0xffff) LOG(LOG_DOSMISC,LOG_ERROR)("Corrupt UMB chain: %x",umb_start); + DOS_CompressMemory(); }; @@ -65,7 +81,15 @@ void DOS_SetMemAllocStrategy(Bit16u strat) bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) { DOS_CompressMemory(); - Bit16u bigsize=0;Bit16u mcb_segment=dos.firstMCB; + Bit16u bigsize=0; + Bit16u mem_strat=memAllocStrategy; + Bit16u mcb_segment=dos.firstMCB; + + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + if (umb_start==UMB_START_SEG) { + if (mem_strat&0xc0) mcb_segment=umb_start; + } else if (umb_start!=0xffff) LOG(LOG_DOSMISC,LOG_ERROR)("Corrupt UMB chain: %x",umb_start); + DOS_MCB mcb(0); DOS_MCB mcb_next(0); DOS_MCB psp_mcb(dos.psp()-1); @@ -88,7 +112,7 @@ bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) { } else { // TODO: Strategy "1": Best matching block /* If so allocate it */ - if ((memAllocStrategy & 0x03)==0) { + if ((mem_strat & 0x03)==0) { mcb_next.SetPt((Bit16u)(mcb_segment+*blocks+1)); mcb_next.SetPSPSeg(MCB_FREE); mcb_next.SetType(mcb.GetType()); @@ -119,11 +143,15 @@ bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) { } /* Onward to the next MCB if there is one */ if (mcb.GetType()==0x5a) { - *blocks=bigsize; - DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); - return false; - } - mcb_segment+=mcb.GetSize()+1; + if ((mem_strat&0x80) && (umb_start==UMB_START_SEG)) { + mcb_segment=dos.firstMCB; + mem_strat&=(~0xc0); + } else { + *blocks=bigsize; + DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); + return false; + } + } else mcb_segment+=mcb.GetSize()+1; } return false; } @@ -210,6 +238,109 @@ bool DOS_FreeMemory(Bit16u segment) { } +void DOS_BuildUMBChain(const char* use_umbs,bool ems_active) { + if (strcmp(use_umbs,"false")!=0) { + Bit16u first_umb_seg=0xca00; + Bit16u first_umb_size=0x600; + + if (strcmp(use_umbs,"max")==0) { + first_umb_seg-=0x100; + first_umb_size+=0x100; + } + + dos_infoblock.SetStartOfUMBChain(UMB_START_SEG); + dos_infoblock.SetUMBChainState(0); // UMBs not linked yet + + DOS_MCB umb_mcb(first_umb_seg); + umb_mcb.SetPSPSeg(0); // currently free + umb_mcb.SetSize(first_umb_size-1); + umb_mcb.SetType(0x5a); + + /* Scan MCB-chain for last block */ + Bit16u mcb_segment=dos.firstMCB; + DOS_MCB mcb(mcb_segment); + while (mcb.GetType()!=0x5a) { + mcb_segment+=mcb.GetSize()+1; + mcb.SetPt(mcb_segment); + } + + /* A system MCB has to cover the space between the + regular MCB-chain and the UMBs */ + Bit16u cover_mcb=(Bit16u)(mcb_segment+mcb.GetSize()+1); + mcb.SetPt(cover_mcb); + mcb.SetType(0x4d); + mcb.SetPSPSeg(0x0008); + mcb.SetSize(first_umb_seg-cover_mcb-1); + mcb.SetFileName("SC "); + + if (!ems_active && (strcmp(use_umbs,"max")==0)) { + Bit16u ems_umb_seg=0xe000; + Bit16u ems_umb_size=0x1000; + + /* Continue UMB-chain */ + umb_mcb.SetSize(first_umb_size-2); + umb_mcb.SetType(0x4d); + + DOS_MCB umb2_mcb(ems_umb_seg); + umb2_mcb.SetPSPSeg(0); // currently free + umb2_mcb.SetSize(ems_umb_size-1); + umb2_mcb.SetType(0x5a); + + /* A system MCB has to take out the space between the previous and this UMB */ + cover_mcb=(Bit16u)(first_umb_seg+umb_mcb.GetSize()+1); + mcb.SetPt(cover_mcb); + mcb.SetType(0x4d); + mcb.SetPSPSeg(0x0008); + mcb.SetSize(ems_umb_seg-cover_mcb-1); + mcb.SetFileName("SC "); + } + } else { + dos_infoblock.SetStartOfUMBChain(0xffff); + dos_infoblock.SetUMBChainState(0); + } +} + +bool DOS_LinkUMBsToMemChain(Bit16u linkstate) { + /* Get start of UMB-chain */ + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + if (umb_start!=UMB_START_SEG) { + if (umb_start!=0xffff) LOG(LOG_DOSMISC,LOG_ERROR)("Corrupt UMB chain: %x",umb_start); + return true; + } + + if ((linkstate&1)==(dos_infoblock.GetUMBChainState()&1)) return true; + + /* Scan MCB-chain for last block before UMB-chain */ + Bit16u mcb_segment=dos.firstMCB; + Bit16u prev_mcb_segment; + DOS_MCB mcb(mcb_segment); + while ((mcb_segment!=umb_start) && (mcb.GetType()!=0x5a)) { + prev_mcb_segment=mcb_segment; + mcb_segment+=mcb.GetSize()+1; + mcb.SetPt(mcb_segment); + } + DOS_MCB prev_mcb(prev_mcb_segment); + + switch (linkstate) { + case 0x0000: // unlink + if ((prev_mcb.GetType()==0x4d) && (mcb_segment==umb_start)) { + prev_mcb.SetType(0x5a); + } + dos_infoblock.SetUMBChainState(0); + break; + case 0x0001: // link + if (mcb.GetType()==0x5a) { + mcb.SetType(0x4d); + dos_infoblock.SetUMBChainState(1); + } + break; + default: + LOG_MSG("Invalid link state %x when reconfiguring MCB chain",linkstate); + return false; + } + + return true; +} void DOS_SetupMemory(void) { @@ -218,6 +349,7 @@ void DOS_SetupMemory(void) { mcb_devicedummy.SetPSPSeg(0x0008); // Devices mcb_devicedummy.SetSize(1); mcb_devicedummy.SetType(0x4d); // More blocks will follow +// mcb_devicedummy.SetFileName("SD "); // BioMenace (segment of int2<0x8000) mem_writeb((DOS_MEM_START+1)<<4,0xcf);// iret diff --git a/src/dos/dos_programs.cpp b/src/dos/dos_programs.cpp index f97e98f0..668069c7 100644 --- a/src/dos/dos_programs.cpp +++ b/src/dos/dos_programs.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_programs.cpp,v 1.38 2005-07-20 11:35:53 qbix79 Exp $ */ +/* $Id: dos_programs.cpp,v 1.39 2005-08-08 13:33:45 c2woody Exp $ */ #include #include @@ -207,9 +207,40 @@ public: void Run(void) { /* Show conventional Memory */ WriteOut("\n"); + + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + Bit8u umb_flag=dos_infoblock.GetUMBChainState(); + Bit8u old_memstrat=DOS_GetMemAllocStrategy()&0xff; + if (umb_start!=0xffff) { + if ((umb_flag&1)==1) DOS_LinkUMBsToMemChain(0); + DOS_SetMemAllocStrategy(0); + } + Bit16u seg,blocks;blocks=0xffff; DOS_AllocateMemory(&seg,&blocks); WriteOut(MSG_Get("PROGRAM_MEM_CONVEN"),blocks*16/1024); + + if (umb_start!=0xffff) { + DOS_LinkUMBsToMemChain(1); + DOS_SetMemAllocStrategy(0x40); // search in UMBs only + + Bit16u largest_block=0,total_blocks=0,block_count=0; + for (;; block_count++) { + blocks=0xffff; + DOS_AllocateMemory(&seg,&blocks); + if (blocks==0) break; + total_blocks+=blocks; + if (blocks>largest_block) largest_block=blocks; + DOS_AllocateMemory(&seg,&blocks); + } + + Bit8u current_umb_flag=dos_infoblock.GetUMBChainState(); + if ((current_umb_flag&1)!=(umb_flag&1)) DOS_LinkUMBsToMemChain(umb_flag); + DOS_SetMemAllocStrategy(old_memstrat); // restore strategy + + if (block_count>0) WriteOut(MSG_Get("PROGRAM_MEM_UPPER"),total_blocks*16/1024,block_count,largest_block*16/1024); + } + /* Test for and show free XMS */ reg_ax=0x4300;CALLBACK_RunRealInt(0x2f); if (reg_al==0x80) { @@ -695,6 +726,7 @@ void DOS_SetupPrograms(void) { MSG_Add("PROGRAM_MEM_CONVEN","%10d Kb free conventional memory\n"); MSG_Add("PROGRAM_MEM_EXTEND","%10d Kb free extended memory\n"); MSG_Add("PROGRAM_MEM_EXPAND","%10d Kb free expanded memory\n"); + MSG_Add("PROGRAM_MEM_UPPER","%10d Kb free upper memory in %d blocks (largest UMB %d Kb)\n"); MSG_Add("PROGRAM_LOADFIX_ALLOC","%d kb allocated.\n"); MSG_Add("PROGRAM_LOADFIX_DEALLOC","%d kb freed.\n"); diff --git a/src/dos/dos_tables.cpp b/src/dos/dos_tables.cpp index 6cd6f9ad..a2bd7754 100644 --- a/src/dos/dos_tables.cpp +++ b/src/dos/dos_tables.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_tables.cpp,v 1.19 2005-08-01 09:30:45 c2woody Exp $ */ +/* $Id: dos_tables.cpp,v 1.20 2005-08-08 13:33:46 c2woody Exp $ */ #include "dosbox.h" #include "mem.h" @@ -100,15 +100,6 @@ void DOS_SetupTables(void) { real_writed(seg,0x0e,0x20202020); // driver name dos_infoblock.SetDeviceChainStart(RealMake(seg,0)); - /* Create a fake SFT, so programs think there are 100 file handles */ - seg=DOS_SFT_SEG; - seg2=DOS_SFT_SEG+1; - real_writed(seg,0,seg2<<16); //Next File Table - real_writew(seg,4,100); //File Table supports 100 files - real_writed(seg2,0,0xffffffff); //Last File Table - real_writew(seg2,4,100); //File Table supports 100 files - dos_infoblock.SetfirstFileTable(RealMake(seg,0)); - /* Create a fake Current Directory Structure */ seg=DOS_CDS_SEG; real_writed(seg,0x00,0x005c3a43); diff --git a/src/dosbox.cpp b/src/dosbox.cpp index 4cc4c2d1..bb4a9aa8 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dosbox.cpp,v 1.86 2005-07-30 14:41:31 qbix79 Exp $ */ +/* $Id: dosbox.cpp,v 1.87 2005-08-08 13:33:46 c2woody Exp $ */ #include #include @@ -379,9 +379,11 @@ void DOSBOX_Init(void) { secprop->Add_bool("xms",true); secprop->AddInitFunction(&EMS_Init,true);//done secprop->Add_bool("ems",true); + secprop->Add_string("umb","true"); MSG_Add("DOS_CONFIGFILE_HELP", "xms -- Enable XMS support.\n" "ems -- Enable EMS support.\n" + "umb -- Enable UMB support (false,true,max).\n" ); // Mscdex secprop->AddInitFunction(&MSCDEX_Init); diff --git a/src/ints/xms.cpp b/src/ints/xms.cpp index 3b2f683e..e33e7b64 100644 --- a/src/ints/xms.cpp +++ b/src/ints/xms.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: xms.cpp,v 1.35 2005-03-25 11:59:24 qbix79 Exp $ */ +/* $Id: xms.cpp,v 1.36 2005-08-08 13:33:46 c2woody Exp $ */ #include #include @@ -55,6 +55,7 @@ #define XMS_QUERY_ANY_FREE_MEMORY 0x88 #define XMS_ALLOCATE_ANY_MEMORY 0x89 +#define XMS_FUNCTION_NOT_IMPLEMENTED 0x80 #define HIGH_MEMORY_NOT_EXIST 0x90 #define HIGH_MEMORY_IN_USE 0x91 #define HIGH_MEMORY_NOT_ALLOCATED 0x93 @@ -63,6 +64,8 @@ #define XMS_INVALID_HANDLE 0xa2 #define XMS_BLOCK_NOT_LOCKED 0xaa #define XMS_BLOCK_LOCKED 0xab +#define UMB_ONLY_SMALLER_BLOCK 0xb0 +#define UMB_NO_BLOCKS_AVAILABLE 0xb1 struct XMS_Block { Bitu size; @@ -102,6 +105,7 @@ Bitu XMS_GetEnabledA20(void) }; static RealPt xms_callback; +static bool umb_available; static XMS_Block xms_handles[XMS_HANDLES]; @@ -322,13 +326,57 @@ Bitu XMS_Handler(void) { reg_bl = XMS_ResizeMemory(reg_dx, reg_bx); reg_ax = (reg_bl==0); break; - case XMS_ALLOCATE_UMB: /* 10 */ - reg_ax=0; - reg_bl=0xb1; //No UMB Available - reg_dx=0; + case XMS_ALLOCATE_UMB: { /* 10 */ + if (!umb_available) { + reg_ax=0; + reg_bl=XMS_FUNCTION_NOT_IMPLEMENTED; + break; + } + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + if (umb_start==0xffff) { + reg_ax=0; + reg_bl=UMB_NO_BLOCKS_AVAILABLE; + reg_dx=0; // no upper memory available + break; + } + /* Save status and linkage of upper UMB chain and link upper + memory to the regular MCB chain */ + Bit8u umb_flag=dos_infoblock.GetUMBChainState(); + if ((umb_flag&1)==0) DOS_LinkUMBsToMemChain(1); + Bit8u old_memstrat=DOS_GetMemAllocStrategy()&0xff; + DOS_SetMemAllocStrategy(0x40); // search in UMBs only + + Bit16u size=reg_dx;Bit16u seg; + if (DOS_AllocateMemory(&seg,&size)) { + reg_ax=1; + reg_bx=seg; + } else { + reg_ax=0; + if (size==0) reg_bl=UMB_NO_BLOCKS_AVAILABLE; + else reg_bl=UMB_ONLY_SMALLER_BLOCK; + reg_dx=size; // size of largest available UMB + } + + /* Restore status and linkage of upper UMB chain */ + Bit8u current_umb_flag=dos_infoblock.GetUMBChainState(); + if ((current_umb_flag&1)!=(umb_flag&1)) DOS_LinkUMBsToMemChain(umb_flag); + DOS_SetMemAllocStrategy(old_memstrat); + } break; case XMS_DEALLOCATE_UMB: /* 11 */ - LOG(LOG_MISC,LOG_ERROR)("XMS:Unhandled call %2X",reg_ah); + if (!umb_available) { + reg_ax=0; + reg_bl=XMS_FUNCTION_NOT_IMPLEMENTED; + break; + } + if (dos_infoblock.GetStartOfUMBChain()!=0xffff) { + if (DOS_FreeMemory(reg_dx)) { + reg_ax=0x0001; + break; + } + } + reg_ax=0x0000; + reg_bl=UMB_NO_BLOCKS_AVAILABLE; break; case XMS_QUERY_ANY_FREE_MEMORY: /* 88 */ reg_bl = XMS_QueryFreeMemory(reg_ax,reg_dx); @@ -336,6 +384,10 @@ Bitu XMS_Handler(void) { reg_edx &= 0xffff; reg_ecx = (MEM_TotalPages()*MEM_PAGESIZE)-1; // highest known physical memory address break; + default: + LOG(LOG_MISC,LOG_ERROR)("XMS: unknown function %02X",reg_ah); + reg_ax=0; + reg_bl=XMS_FUNCTION_NOT_IMPLEMENTED; } // LOG(LOG_MISC,LOG_ERROR)("XMS: CALL Result: %02X",reg_bl); return CBRET_NONE; @@ -346,6 +398,7 @@ private: public: XMS(Section* configuration):Module_base(configuration){ Section_prop * section=static_cast(configuration); + umb_available=false; if (!section->Get_bool("xms")) return; Bitu i; BIOS_ZeroExtendedSize(true); @@ -373,10 +426,21 @@ public: } /* Disable the 0 handle */ xms_handles[0].free = false; + + /* Set up UMB chain */ + umb_available=strcmp(section->Get_string("umb"),"false")!=0; + DOS_BuildUMBChain(section->Get_string("umb"),section->Get_bool("ems")); } ~XMS(){ Section_prop * section = static_cast(m_configuration); + /* Remove upper memory information */ + dos_infoblock.SetStartOfUMBChain(0xffff); + if (umb_available) { + dos_infoblock.SetUMBChainState(0); + umb_available=false; + } + if (!section->Get_bool("xms")) return; /* Undo biosclearing */ BIOS_ZeroExtendedSize(false);