From 57c02611d7a3c6bb5f13a8b1ae9bd4629478b7a1 Mon Sep 17 00:00:00 2001 From: Sjoerd van der Berg Date: Wed, 21 Aug 2002 14:20:18 +0000 Subject: [PATCH] EMM completely redone for new memory system, 3.2 EMM Manager support Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@197 --- src/ints/ems.cpp | 368 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 283 insertions(+), 85 deletions(-) diff --git a/src/ints/ems.cpp b/src/ints/ems.cpp index 705334c8..3dafc2ef 100644 --- a/src/ints/ems.cpp +++ b/src/ints/ems.cpp @@ -18,6 +18,7 @@ #include +#include #include "dosbox.h" #include "callback.h" #include "mem.h" @@ -28,105 +29,296 @@ #include "dos_inc.h" -#define PAGEFRAME_SEG 0xe000 +#define EMM_PAGEFRAME 0xE000 +#define EMM_MAX_HANDLES 50 /* 255 Max */ +#define EMM_PAGE_SIZE (16*1024) +#define EMM_MAX_PAGES (C_MEM_EMS_SIZE * 1024 / 16 ) +#define EMM_MAX_PHYS 4 /* 4 16kb pages in pageframe */ -class device_EMS : public DOS_Device { +#define EMM_VERSION 0x32 + +#define NULL_HANDLE 0xffff +#define NULL_PAGE 0xffff + +/* EMM errors */ +#define EMM_NO_ERROR 0x00 +#define EMM_SOFT_MAL 0x80 +#define EMM_HARD_MAL 0x81 +#define EMM_INVALID_HANDLE 0x83 +#define EMM_FUNC_NOSUP 0x84 +#define EMM_OUT_OF_HANDLES 0x85 +#define EMM_OUT_OF_PHYS 0x87 +#define EMM_OUT_OF_LOG 0x88 +#define EMM_ZERO_PAGES 0x89 +#define EMM_LOG_OUT_RANGE 0x8a +#define EMM_ILL_PHYS 0x8b +#define EMM_PAGE_MAP_SAVED 0x8d +#define EMM_INVALID_SUB 0x8f +#define EMM_FEAT_NOSUP 0x91 +#define EMM_MOVE_OVLAP 0x92 +#define EMM_MOVE_OVLAPI 0x97 +#define EMM_NOT_FOUND 0xa0 + + +class device_EMM : public DOS_Device { public: - device_EMS(); - bool Read(Bit8u * data,Bit16u * size); - bool Write(Bit8u * data,Bit16u * size); - bool Seek(Bit32u * pos,Bit32u type); - bool Close(); - Bit16u GetInformation(void); + device_EMM(){name="EMMXXXX0";} + bool Read(Bit8u * data,Bit16u * size) { return false;} + bool Write(Bit8u * data,Bit16u * size){ + LOG_DEBUG("Write to ems device"); + return false; + } + bool Seek(Bit32u * pos,Bit32u type){return false;} + bool Close(){return false;} + Bit16u GetInformation(void){return 0x8093;} private: Bit8u cache; }; +device_EMM::device_EMM(); -bool device_EMS::Read(Bit8u * data,Bit16u * size) { - return false; -} - -bool device_EMS::Write(Bit8u * data,Bit16u * size) { - return false; -} - -bool device_EMS::Seek(Bit32u * pos,Bit32u type) { - return false; -} - -bool device_EMS::Close() { - return false; -} - -Bit16u device_EMS::GetInformation(void) { - return 0x8093; +struct EMM_Mapping { + Bit16u handle; + Bit16u page; }; -device_EMS::device_EMS() { - name="EMMXXXX0"; +struct EMM_Page { + void * memory; + Bit16u handle; + Bit16u next; +}; + +struct EMM_Handle { + Bit16u first_page; + Bit16u pages; + char name[9]; + bool saved_page_map; + EMM_Mapping page_map[EMM_MAX_PHYS]; +}; + +static EMM_Handle emm_handles[EMM_MAX_HANDLES]; +static EMM_Page emm_pages[EMM_MAX_PAGES]; +static EMM_Mapping emm_mappings[EMM_MAX_PHYS]; +Bitu call_int67; + +static Bit16u EMM_GetFreePages(void) { + Bit16u count=0; + for (Bitu index=0;index=EMM_MAX_HANDLES) {handle=NULL_HANDLE;return EMM_OUT_OF_HANDLES;} + } + /* Allocate the pages */ + Bit16u page=0;Bit16u last=NULL_PAGE; + emm_handles[handle].pages=pages; + while (pages) { + if (emm_pages[page].handle==NULL_HANDLE) { + emm_pages[page].handle=handle; + emm_pages[page].memory=malloc(EMM_PAGE_SIZE); + if (!emm_pages[page].memory) E_Exit("EMM:Cannont allocate memory"); + if (last!=NULL_PAGE) emm_pages[last].next=page; + else emm_handles[handle].first_page=page; + last=page; + pages--; + } else { + if (++page>=EMM_MAX_PAGES) E_Exit("EMM:Ran out of pages"); + } + } + return EMM_NO_ERROR; +} -PageEntry ems_entries[4]; +static Bit8u EMM_MapPage(Bitu phys_page,Bit16u handle,Bit16u log_page) { + /* Check for too high physical page */ + if (phys_page>=EMM_MAX_PHYS) return EMM_ILL_PHYS; + /* Check for valid handle */ + if (handle>=EMM_MAX_HANDLES || emm_handles[handle].first_page==NULL_PAGE) return EMM_INVALID_HANDLE; + /* Check to do unmapping or mappning */ + if (log_page=EMM_MAX_HANDLES || emm_handles[handle].first_page==NULL_PAGE) return EMM_INVALID_HANDLE; + Bit16u page=emm_handles[handle].first_page; + Bit16u pages=emm_handles[handle].pages; + while (pages) { + free(emm_pages[page].memory); + emm_pages[page].memory=0; + emm_pages[page].handle=NULL_HANDLE; + Bit16u next_page=emm_pages[page].next; + emm_pages[page].next=NULL_PAGE; + page=next_page;pages--; + } + /* Reset handle */ + emm_handles[handle].first_page=NULL_PAGE; + emm_handles[handle].pages=0; + emm_handles[handle].saved_page_map=false; + memset(&emm_handles[handle].name,0,9); + return EMM_NO_ERROR; +} + +static Bit8u EMM_SavePageMap(Bit16u handle) { + /* Check for valid handle */ + if (handle>=EMM_MAX_HANDLES || emm_handles[handle].first_page==NULL_PAGE) return EMM_INVALID_HANDLE; + /* Check for previous save */ + if (emm_handles[handle].saved_page_map) return EMM_PAGE_MAP_SAVED; + /* Copy the mappings over */ + for (Bitu i=0;i=EMM_MAX_HANDLES || emm_handles[handle].first_page==NULL_PAGE) return EMM_INVALID_HANDLE; + /* Check for previous save */ + if (!emm_handles[handle].saved_page_map) return EMM_INVALID_HANDLE; + /* Restore the mappings */ + emm_handles[handle].saved_page_map=false; + for (Bitu i=0;i>2; - reg_bx=total>>2; - reg_ah=0; - }; + reg_dx=EMM_MAX_PAGES; + reg_bx=EMM_GetFreePages(); + reg_ah=EMM_NO_ERROR; break; case 0x43: /* Get Handle and Allocate Pages */ - { - if (!reg_bx) { reg_ah=0x89;break; } - Bit16u handle; - EMM_Allocate(reg_bx*4,&handle); - if (handle) { - reg_ah=0; - reg_dx=handle; - } else { reg_ah=0x88; } - break; - } - case 0x44: /* Map Memory */ - { - if (reg_al>3) { reg_ah=0x8b;break; } - HostPt pagestart=memory+EMM_Handles[reg_dx].phys_base+reg_bx*16*1024; - ems_entries[reg_al].relocate=pagestart; - reg_ah=0; - break; - } - case 0x45: /* Release handle and free pages */ - EMM_Free(reg_dx); - reg_ah=0; - break; - case 0x46: /* Get EMM Version */ - reg_ah=0; - reg_al=0x32; //Only 3.2 support for now + reg_ah=EMM_AllocateMemory(reg_bx,reg_dx); break; - case 0x47: /* Save Mapping Context */ - LOG_ERROR("EMS:47:Save Mapping Context not supported"); - reg_ah=0x8c; + case 0x44: /* Map Expanded Memory Page */ + reg_ah=EMM_MapPage(reg_al,reg_dx,reg_bx); + break; + case 0x45: /* Release handle and free pages */ + reg_ah=EMM_ReleaseMemory(reg_dx); + break; + case 0x46: /* Get EMM Version */ + reg_ah=EMM_NO_ERROR; + reg_al=EMM_VERSION; + break; + case 0x47: /* Save Page Map */ + reg_ah=EMM_SavePageMap(reg_dx); + break; + case 0x48: /* Restore Page Map */ + reg_ah=EMM_RestorePageMap(reg_dx); + break; + case 0x4b: /* Get Handle Count */ + reg_bx=0; + for (i=0;i=EMM_MAX_HANDLES || emm_handles[reg_bx].first_page==NULL_PAGE) {reg_ah=EMM_INVALID_HANDLE;break;} + reg_bx=emm_handles[reg_dx].pages; + reg_ah=EMM_NO_ERROR; + break; + case 0x4d: /* Get Pages for all Handles */ + reg_ah=EMM_GetPagesForAllHandles(SegPhys(es)+reg_di,reg_bx); + break; + case 0x4e: /*Save/Restore Page Map */ + LOG_WARN("Save/resetore %d",reg_al); + switch (reg_al) { + case 0x00: /* Save Page Map */ + MEM_BlockWrite(SegPhys(es)+reg_di,emm_mappings,sizeof(emm_mappings)); + reg_ah=EMM_NO_ERROR; + break; + case 0x01: /* Restore Page Map */ + MEM_BlockRead(SegPhys(ds)+reg_si,emm_mappings,sizeof(emm_mappings)); + reg_ah=EMM_RestoreMappingTable(); + break; + case 0x02: /* Save and Restore Page Map */ + MEM_BlockWrite(SegPhys(es)+reg_di,emm_mappings,sizeof(emm_mappings)); + MEM_BlockRead(SegPhys(ds)+reg_si,emm_mappings,sizeof(emm_mappings)); + reg_ah=EMM_RestoreMappingTable(); + break; + case 0x03: /* Get Page Map Array Size */ + reg_al=sizeof(emm_mappings); + reg_ah=EMM_NO_ERROR; + break; + default: + LOG_ERROR("EMS:Call %2X Subfunction %2X not supported",reg_ah,reg_al); + reg_ah=EMM_FUNC_NOSUP; + break; + } break; case 0xDE: /* VCPI Functions */ LOG_ERROR("VCPI Functions not supported"); - reg_ah=0x8c; + reg_ah=EMM_FUNC_NOSUP; break; default: LOG_ERROR("EMS:Call %2X not supported",reg_ah); - reg_ah=0x8c; + reg_ah=EMM_FUNC_NOSUP; break; } return CBRET_NONE; @@ -138,28 +330,34 @@ void EMS_Init(void) { call_int67=CALLBACK_Allocate(); CALLBACK_Setup(call_int67,&INT67_Handler,CB_IRET); /* Register the ems device */ - DOS_Device * newdev = new device_EMS(); + DOS_Device * newdev = new device_EMM(); DOS_AddDevice(newdev); -/* Setup the page handlers for the page frame */ - for (Bitu i=0;i<4;i++) { - ems_entries[i].base=(PAGEFRAME_SEG<<4)+i*16*1024; - ems_entries[i].type=MEMORY_RELOCATE; - ems_entries[i].relocate=memory+(PAGEFRAME_SEG<<4)+i*16*1024; -/* Place the page handlers in the ems page fram piece of the memory handler*/ - MEMORY_SetupHandler(((PAGEFRAME_SEG<<4)+i*16*1024)>>12,4,&ems_entries[i]); - } /* Add a little hack so it appears that there is an actual ems device installed */ char * emsname="EMMXXXX0"; Bit16u seg=DOS_GetMemory(2); //We have 32 bytes - MEM_BlockWrite(real_phys(seg,0xa),emsname,strlen(emsname)+1); -/* Copy the callback piece into the beginning */ + MEM_BlockWrite(PhysMake(seg,0xa),emsname,strlen(emsname)+1); +/* Copy the callback piece into the beginning, and set the interrupt vector to it*/ char buf[16]; - MEM_BlockRead(real_phys(CB_SEG,call_int67<<4),buf,0xa); - MEM_BlockWrite(real_phys(seg,0),buf,0xa); - + MEM_BlockRead(PhysMake(CB_SEG,call_int67<<4),buf,0xa); + MEM_BlockWrite(PhysMake(seg,0),buf,0xa); RealSetVec(0x67,RealMake(seg,0)); +/* Clear handle and page tables */ + Bitu i; + for (i=0;i