// // ID_PM.C // Id Engine's Page Manager v1.0 // Primary coder: Jason Blochowiak // #include "ID_HEADS.H" #pragma hdrstop // Main Mem specific variables boolean MainPresent; memptr MainMemPages[PMMaxMainMem]; PMBlockAttr MainMemUsed[PMMaxMainMem]; int MainPagesAvail; // EMS specific variables boolean EMSPresent; word EMSAvail,EMSPagesAvail,EMSHandle, EMSPageFrame,EMSPhysicalPage; EMSListStruct EMSList[EMSFrameCount]; // XMS specific variables boolean XMSPresent; word XMSAvail,XMSPagesAvail,XMSHandle; longword XMSDriver; int XMSProtectPage = -1; // File specific variables char PageFileName[13] = {"VSWAP."}; int PageFile = -1; word ChunksInFile; word PMSpriteStart,PMSoundStart; // General usage variables boolean PMStarted, PMPanicMode, PMThrashing; word XMSPagesUsed, EMSPagesUsed, MainPagesUsed, PMNumBlocks; long PMFrameCount; PageListStruct far *PMPages, _seg *PMSegPages; static char *ParmStrings[] = {"nomain","noems","noxms",nil}; ///////////////////////////////////////////////////////////////////////////// // // EMS Management code // ///////////////////////////////////////////////////////////////////////////// // // PML_MapEMS() - Maps a logical page to a physical page // void PML_MapEMS(word logical,word physical) { _AL = physical; _BX = logical; _DX = EMSHandle; _AH = EMS_MAPPAGE; asm int EMS_INT if (_AH) Quit("PML_MapEMS: Page mapping failed"); } // // PML_StartupEMS() - Sets up EMS for Page Mgr's use // Checks to see if EMS driver is present // Verifies that EMS hardware is present // Make sure that EMS version is 3.2 or later // If there's more than our minimum (2 pages) available, allocate it (up // to the maximum we need) // char EMMDriverName[9] = "EMMXXXX0"; boolean PML_StartupEMS(void) { int i; long size; EMSPresent = false; // Assume that we'll fail EMSAvail = 0; _DX = (word)EMMDriverName; _AX = 0x3d00; geninterrupt(0x21); // try to open EMMXXXX0 device asm jnc gothandle goto error; gothandle: _BX = _AX; _AX = 0x4400; geninterrupt(0x21); // get device info asm jnc gotinfo; goto error; gotinfo: asm and dx,0x80 if (!_DX) goto error; _AX = 0x4407; geninterrupt(0x21); // get status asm jc error if (!_AL) goto error; _AH = 0x3e; geninterrupt(0x21); // close handle _AH = EMS_STATUS; geninterrupt(EMS_INT); if (_AH) goto error; // make sure EMS hardware is present _AH = EMS_VERSION; geninterrupt(EMS_INT); if (_AH || (_AL < 0x32)) // only work on EMS 3.2 or greater (silly, but...) goto error; _AH = EMS_GETFRAME; geninterrupt(EMS_INT); if (_AH) goto error; // find the page frame address EMSPageFrame = _BX; _AH = EMS_GETPAGES; geninterrupt(EMS_INT); if (_AH) goto error; if (_BX < 2) goto error; // Require at least 2 pages (32k) EMSAvail = _BX; // Don't hog all available EMS size = EMSAvail * (long)EMSPageSize; if (size - (EMSPageSize * 2) > (ChunksInFile * (long)PMPageSize)) { size = (ChunksInFile * (long)PMPageSize) + EMSPageSize; EMSAvail = size / EMSPageSize; } _AH = EMS_ALLOCPAGES; _BX = EMSAvail; geninterrupt(EMS_INT); if (_AH) goto error; EMSHandle = _DX; mminfo.EMSmem += EMSAvail * (long)EMSPageSize; // Initialize EMS mapping cache for (i = 0;i < EMSFrameCount;i++) EMSList[i].baseEMSPage = -1; EMSPresent = true; // We have EMS error: return(EMSPresent); } // // PML_ShutdownEMS() - If EMS was used, deallocate it // void PML_ShutdownEMS(void) { if (EMSPresent) { asm mov ah,EMS_FREEPAGES asm mov dx,[EMSHandle] asm int EMS_INT if (_AH) Quit ("PML_ShutdownEMS: Error freeing EMS"); } } ///////////////////////////////////////////////////////////////////////////// // // XMS Management code // ///////////////////////////////////////////////////////////////////////////// // // PML_StartupXMS() - Starts up XMS for the Page Mgr's use // Checks for presence of an XMS driver // Makes sure that there's at least a page of XMS available // Allocates any remaining XMS (rounded down to the nearest page size) // boolean PML_StartupXMS(void) { XMSPresent = false; // Assume failure XMSAvail = 0; asm mov ax,0x4300 asm int XMS_INT // Check for presence of XMS driver if (_AL != 0x80) goto error; asm mov ax,0x4310 asm int XMS_INT // Get address of XMS driver asm mov [WORD PTR XMSDriver],bx asm mov [WORD PTR XMSDriver+2],es // function pointer to XMS driver XMS_CALL(XMS_QUERYFREE); // Find out how much XMS is available XMSAvail = _AX; if (!_AX) // AJR: bugfix 10/8/92 goto error; XMSAvail &= ~(PMPageSizeKB - 1); // Round off to nearest page size if (XMSAvail < (PMPageSizeKB * 2)) // Need at least 2 pages goto error; _DX = XMSAvail; XMS_CALL(XMS_ALLOC); // And do the allocation XMSHandle = _DX; if (!_AX) // AJR: bugfix 10/8/92 { XMSAvail = 0; goto error; } mminfo.XMSmem += XMSAvail * 1024; XMSPresent = true; error: return(XMSPresent); } // // PML_XMSCopy() - Copies a main/EMS page to or from XMS // Will round an odd-length request up to the next even value // void PML_XMSCopy(boolean toxms,byte far *addr,word xmspage,word length) { longword xoffset; struct { longword length; word source_handle; longword source_offset; word target_handle; longword target_offset; } copy; if (!addr) Quit("PML_XMSCopy: zero address"); xoffset = (longword)xmspage * PMPageSize; copy.length = (length + 1) & ~1; copy.source_handle = toxms? 0 : XMSHandle; copy.source_offset = toxms? (long)addr : xoffset; copy.target_handle = toxms? XMSHandle : 0; copy.target_offset = toxms? xoffset : (long)addr; asm push si _SI = (word)© XMS_CALL(XMS_MOVE); asm pop si if (!_AX) Quit("PML_XMSCopy: Error on copy"); } #if 1 #define PML_CopyToXMS(s,t,l) PML_XMSCopy(true,(s),(t),(l)) #define PML_CopyFromXMS(t,s,l) PML_XMSCopy(false,(t),(s),(l)) #else // // PML_CopyToXMS() - Copies the specified number of bytes from the real mode // segment address to the specified XMS page // void PML_CopyToXMS(byte far *source,int targetpage,word length) { PML_XMSCopy(true,source,targetpage,length); } // // PML_CopyFromXMS() - Copies the specified number of bytes from an XMS // page to the specified real mode address // void PML_CopyFromXMS(byte far *target,int sourcepage,word length) { PML_XMSCopy(false,target,sourcepage,length); } #endif // // PML_ShutdownXMS() // void PML_ShutdownXMS(void) { if (XMSPresent) { _DX = XMSHandle; XMS_CALL(XMS_FREE); if (_BL) Quit("PML_ShutdownXMS: Error freeing XMS"); } } ///////////////////////////////////////////////////////////////////////////// // // Main memory code // ///////////////////////////////////////////////////////////////////////////// // // PM_SetMainMemPurge() - Sets the purge level for all allocated main memory // blocks. This shouldn't be called directly - the PM_LockMainMem() and // PM_UnlockMainMem() macros should be used instead. // void PM_SetMainMemPurge(int level) { int i; for (i = 0;i < PMMaxMainMem;i++) if (MainMemPages[i]) MM_SetPurge(&MainMemPages[i],level); } // // PM_CheckMainMem() - If something besides the Page Mgr makes requests of // the Memory Mgr, some of the Page Mgr's blocks may have been purged, // so this function runs through the block list and checks to see if // any of the blocks have been purged. If so, it marks the corresponding // page as purged & unlocked, then goes through the block list and // tries to reallocate any blocks that have been purged. // This routine now calls PM_LockMainMem() to make sure that any allocation // attempts made during the block reallocation sweep don't purge any // of the other blocks. Because PM_LockMainMem() is called, // PM_UnlockMainMem() needs to be called before any other part of the // program makes allocation requests of the Memory Mgr. // void PM_CheckMainMem(void) { boolean allocfailed; int i,n; memptr *p; PMBlockAttr *used; PageListStruct far *page; if (!MainPresent) return; for (i = 0,page = PMPages;i < ChunksInFile;i++,page++) { n = page->mainPage; if (n != -1) // Is the page using main memory? { if (!MainMemPages[n]) // Yep, was the block purged? { page->mainPage = -1; // Yes, mark page as purged & unlocked page->locked = pml_Unlocked; } } } // Prevent allocation attempts from purging any of our other blocks PM_LockMainMem(); allocfailed = false; for (i = 0,p = MainMemPages,used = MainMemUsed;i < PMMaxMainMem;i++,p++,used++) { if (!*p) // If the page got purged { if (*used & pmba_Allocated) // If it was allocated { *used &= ~pmba_Allocated; // Mark as unallocated MainPagesAvail--; // and decrease available count } if (*used & pmba_Used) // If it was used { *used &= ~pmba_Used; // Mark as unused MainPagesUsed--; // and decrease used count } if (!allocfailed) { MM_BombOnError(false); MM_GetPtr(p,PMPageSize); // Try to reallocate if (mmerror) // If it failed, allocfailed = true; // don't try any more allocations else // If it worked, { *used |= pmba_Allocated; // Mark as allocated MainPagesAvail++; // and increase available count } MM_BombOnError(true); } } } if (mmerror) mmerror = false; } // // PML_StartupMainMem() - Allocates as much main memory as is possible for // the Page Mgr. The memory is allocated as non-purgeable, so if it's // necessary to make requests of the Memory Mgr, PM_UnlockMainMem() // needs to be called. // void PML_StartupMainMem(void) { int i,n; memptr *p; MainPagesAvail = 0; MM_BombOnError(false); for (i = 0,p = MainMemPages;i < PMMaxMainMem;i++,p++) { MM_GetPtr(p,PMPageSize); if (mmerror) break; MainPagesAvail++; MainMemUsed[i] = pmba_Allocated; } MM_BombOnError(true); if (mmerror) mmerror = false; if (MainPagesAvail < PMMinMainMem) Quit("PM_SetupMainMem: Not enough main memory"); MainPresent = true; } // // PML_ShutdownMainMem() - Frees all of the main memory blocks used by the // Page Mgr. // void PML_ShutdownMainMem(void) { int i; memptr *p; // DEBUG - mark pages as unallocated & decrease page count as appropriate for (i = 0,p = MainMemPages;i < PMMaxMainMem;i++,p++) if (*p) MM_FreePtr(p); } ///////////////////////////////////////////////////////////////////////////// // // File management code // ///////////////////////////////////////////////////////////////////////////// // // PML_ReadFromFile() - Reads some data in from the page file // void PML_ReadFromFile(byte far *buf,long offset,word length) { if (!buf) Quit("PML_ReadFromFile: Null pointer"); if (!offset) Quit("PML_ReadFromFile: Zero offset"); if (lseek(PageFile,offset,SEEK_SET) != offset) Quit("PML_ReadFromFile: Seek failed"); if (!CA_FarRead(PageFile,buf,length)) Quit("PML_ReadFromFile: Read failed"); } // // PML_OpenPageFile() - Opens the page file and sets up the page info // void PML_OpenPageFile(void) { int i; long size; void _seg *buf; longword far *offsetptr; word far *lengthptr; PageListStruct far *page; PageFile = open(PageFileName,O_RDONLY + O_BINARY); if (PageFile == -1) Quit("PML_OpenPageFile: Unable to open page file"); // Read in header variables read(PageFile,&ChunksInFile,sizeof(ChunksInFile)); read(PageFile,&PMSpriteStart,sizeof(PMSpriteStart)); read(PageFile,&PMSoundStart,sizeof(PMSoundStart)); // Allocate and clear the page list PMNumBlocks = ChunksInFile; MM_GetPtr(&(memptr)PMSegPages,sizeof(PageListStruct) * PMNumBlocks); MM_SetLock(&(memptr)PMSegPages,true); PMPages = (PageListStruct far *)PMSegPages; _fmemset(PMPages,0,sizeof(PageListStruct) * PMNumBlocks); // Read in the chunk offsets size = sizeof(longword) * ChunksInFile; MM_GetPtr(&buf,size); if (!CA_FarRead(PageFile,(byte far *)buf,size)) Quit("PML_OpenPageFile: Offset read failed"); offsetptr = (longword far *)buf; for (i = 0,page = PMPages;i < ChunksInFile;i++,page++) page->offset = *offsetptr++; MM_FreePtr(&buf); // Read in the chunk lengths size = sizeof(word) * ChunksInFile; MM_GetPtr(&buf,size); if (!CA_FarRead(PageFile,(byte far *)buf,size)) Quit("PML_OpenPageFile: Length read failed"); lengthptr = (word far *)buf; for (i = 0,page = PMPages;i < ChunksInFile;i++,page++) page->length = *lengthptr++; MM_FreePtr(&buf); } // // PML_ClosePageFile() - Closes the page file // void PML_ClosePageFile(void) { if (PageFile != -1) close(PageFile); if (PMSegPages) { MM_SetLock(&(memptr)PMSegPages,false); MM_FreePtr(&(void _seg *)PMSegPages); } } ///////////////////////////////////////////////////////////////////////////// // // Allocation, etc., code // ///////////////////////////////////////////////////////////////////////////// // // PML_GetEMSAddress() // // Page is in EMS, so figure out which EMS physical page should be used // to map our page in. If normal page, use EMS physical page 3, else // use the physical page specified by the lock type // #if 1 #pragma argsused // DEBUG - remove lock parameter memptr PML_GetEMSAddress(int page,PMLockType lock) { int i,emspage; word emsoff,emsbase,offset; emsoff = page & (PMEMSSubPage - 1); emsbase = page - emsoff; emspage = -1; // See if this page is already mapped in for (i = 0;i < EMSFrameCount;i++) { if (EMSList[i].baseEMSPage == emsbase) { emspage = i; // Yep - don't do a redundant remapping break; } } // If page isn't already mapped in, find LRU EMS frame, and use it if (emspage == -1) { longword last = MAXLONG; for (i = 0;i < EMSFrameCount;i++) { if (EMSList[i].lastHit < last) { emspage = i; last = EMSList[i].lastHit; } } EMSList[emspage].baseEMSPage = emsbase; PML_MapEMS(page / PMEMSSubPage,emspage); } if (emspage == -1) Quit("PML_GetEMSAddress: EMS find failed"); EMSList[emspage].lastHit = PMFrameCount; offset = emspage * EMSPageSizeSeg; offset += emsoff * PMPageSizeSeg; return((memptr)(EMSPageFrame + offset)); } #else memptr PML_GetEMSAddress(int page,PMLockType lock) { word emspage; emspage = (lock < pml_EMSLock)? 3 : (lock - pml_EMSLock); PML_MapEMS(page / PMEMSSubPage,emspage); return((memptr)(EMSPageFrame + (emspage * EMSPageSizeSeg) + ((page & (PMEMSSubPage - 1)) * PMPageSizeSeg))); } #endif // // PM_GetPageAddress() - Returns the address of a given page // Maps in EMS if necessary // Returns nil if block isn't cached into Main Memory or EMS // // memptr PM_GetPageAddress(int pagenum) { PageListStruct far *page; page = &PMPages[pagenum]; if (page->mainPage != -1) return(MainMemPages[page->mainPage]); else if (page->emsPage != -1) return(PML_GetEMSAddress(page->emsPage,page->locked)); else return(nil); } // // PML_GiveLRUPage() - Returns the page # of the least recently used // present & unlocked main/EMS page (or main page if mainonly is true) // int PML_GiveLRUPage(boolean mainonly) { int i,lru; long last; PageListStruct far *page; for (i = 0,page = PMPages,lru = -1,last = MAXLONG;i < ChunksInFile;i++,page++) { if ( (page->lastHit < last) && ((page->emsPage != -1) || (page->mainPage != -1)) && (page->locked == pml_Unlocked) && (!(mainonly && (page->mainPage == -1))) ) { last = page->lastHit; lru = i; } } if (lru == -1) Quit("PML_GiveLRUPage: LRU Search failed"); return(lru); } // // PML_GiveLRUXMSPage() - Returns the page # of the least recently used // (and present) XMS page. // This routine won't return the XMS page protected (by XMSProtectPage) // int PML_GiveLRUXMSPage(void) { int i,lru; long last; PageListStruct far *page; for (i = 0,page = PMPages,lru = -1,last = MAXLONG;i < ChunksInFile;i++,page++) { if ( (page->xmsPage != -1) && (page->lastHit < last) && (i != XMSProtectPage) ) { last = page->lastHit; lru = i; } } return(lru); } // // PML_PutPageInXMS() - If page isn't in XMS, find LRU XMS page and replace // it with the main/EMS page // void PML_PutPageInXMS(int pagenum) { int usexms; PageListStruct far *page; if (!XMSPresent) return; page = &PMPages[pagenum]; if (page->xmsPage != -1) return; // Already in XMS if (XMSPagesUsed < XMSPagesAvail) page->xmsPage = XMSPagesUsed++; else { usexms = PML_GiveLRUXMSPage(); if (usexms == -1) Quit("PML_PutPageInXMS: No XMS LRU"); page->xmsPage = PMPages[usexms].xmsPage; PMPages[usexms].xmsPage = -1; } PML_CopyToXMS(PM_GetPageAddress(pagenum),page->xmsPage,page->length); } // // PML_TransferPageSpace() - A page is being replaced, so give the new page // the old one's address space. Returns the address of the new page. // memptr PML_TransferPageSpace(int orig,int new) { memptr addr; PageListStruct far *origpage,far *newpage; if (orig == new) Quit("PML_TransferPageSpace: Identity replacement"); origpage = &PMPages[orig]; newpage = &PMPages[new]; if (origpage->locked != pml_Unlocked) Quit("PML_TransferPageSpace: Killing locked page"); if ((origpage->emsPage == -1) && (origpage->mainPage == -1)) Quit("PML_TransferPageSpace: Reusing non-existent page"); // Copy page that's about to be purged into XMS PML_PutPageInXMS(orig); // Get the address, and force EMS into a physical page if necessary addr = PM_GetPageAddress(orig); // Steal the address newpage->emsPage = origpage->emsPage; newpage->mainPage = origpage->mainPage; // Mark replaced page as purged origpage->mainPage = origpage->emsPage = -1; if (!addr) Quit("PML_TransferPageSpace: Zero replacement"); return(addr); } // // PML_GetAPageBuffer() - A page buffer is needed. Either get it from the // main/EMS free pool, or use PML_GiveLRUPage() to find which page to // steal the buffer from. Returns a far pointer to the page buffer, and // sets the fields inside the given page structure appropriately. // If mainonly is true, free EMS will be ignored, and only main pages // will be looked at by PML_GiveLRUPage(). // byte far * PML_GetAPageBuffer(int pagenum,boolean mainonly) { byte far *addr = nil; int i,n; PMBlockAttr *used; PageListStruct far *page; page = &PMPages[pagenum]; if ((EMSPagesUsed < EMSPagesAvail) && !mainonly) { // There's remaining EMS - use it page->emsPage = EMSPagesUsed++; addr = PML_GetEMSAddress(page->emsPage,page->locked); } else if (MainPagesUsed < MainPagesAvail) { // There's remaining main memory - use it for (i = 0,n = -1,used = MainMemUsed;i < PMMaxMainMem;i++,used++) { if ((*used & pmba_Allocated) && !(*used & pmba_Used)) { n = i; *used |= pmba_Used; break; } } if (n == -1) Quit("PML_GetPageBuffer: MainPagesAvail lied"); addr = MainMemPages[n]; if (!addr) Quit("PML_GetPageBuffer: Purged main block"); page->mainPage = n; MainPagesUsed++; } else addr = PML_TransferPageSpace(PML_GiveLRUPage(mainonly),pagenum); if (!addr) Quit("PML_GetPageBuffer: Search failed"); return(addr); } // // PML_GetPageFromXMS() - If page is in XMS, find LRU main/EMS page and // replace it with the page from XMS. If mainonly is true, will only // search for LRU main page. // XMSProtectPage is set to the page to be retrieved from XMS, so that if // the page from which we're stealing the main/EMS from isn't in XMS, // it won't copy over the page that we're trying to get from XMS. // (pages that are being purged are copied into XMS, if possible) // memptr PML_GetPageFromXMS(int pagenum,boolean mainonly) { byte far *checkaddr; memptr addr = nil; PageListStruct far *page; page = &PMPages[pagenum]; if (XMSPresent && (page->xmsPage != -1)) { XMSProtectPage = pagenum; checkaddr = PML_GetAPageBuffer(pagenum,mainonly); if (FP_OFF(checkaddr)) Quit("PML_GetPageFromXMS: Non segment pointer"); addr = (memptr)FP_SEG(checkaddr); PML_CopyFromXMS(addr,page->xmsPage,page->length); XMSProtectPage = -1; } return(addr); } // // PML_LoadPage() - A page is not in main/EMS memory, and it's not in XMS. // Load it into either main or EMS. If mainonly is true, the page will // only be loaded into main. // void PML_LoadPage(int pagenum,boolean mainonly) { byte far *addr; PageListStruct far *page; addr = PML_GetAPageBuffer(pagenum,mainonly); page = &PMPages[pagenum]; PML_ReadFromFile(addr,page->offset,page->length); } // // PM_GetPage() - Returns the address of the page, loading it if necessary // First, check if in Main Memory or EMS // Then, check XMS // If not in XMS, load into Main Memory or EMS // #pragma warn -pia memptr PM_GetPage(int pagenum) { memptr result; if (pagenum >= ChunksInFile) Quit("PM_GetPage: Invalid page request"); #if 0 // for debugging asm mov dx,STATUS_REGISTER_1 asm in al,dx asm mov dx,ATR_INDEX asm mov al,ATR_OVERSCAN asm out dx,al asm mov al,10 // bright green asm out dx,al #endif if (!(result = PM_GetPageAddress(pagenum))) { boolean mainonly = (pagenum >= PMSoundStart); if (!PMPages[pagenum].offset) // JDC: sparse page Quit ("Tried to load a sparse page!"); if (!(result = PML_GetPageFromXMS(pagenum,mainonly))) { if (PMPages[pagenum].lastHit == PMFrameCount) PMThrashing++; PML_LoadPage(pagenum,mainonly); result = PM_GetPageAddress(pagenum); } } PMPages[pagenum].lastHit = PMFrameCount; #if 0 // for debugging asm mov dx,STATUS_REGISTER_1 asm in al,dx asm mov dx,ATR_INDEX asm mov al,ATR_OVERSCAN asm out dx,al asm mov al,3 // blue asm out dx,al asm mov al,0x20 // normal asm out dx,al #endif return(result); } #pragma warn +pia // // PM_SetPageLock() - Sets the lock type on a given page // pml_Unlocked: Normal, page can be purged // pml_Locked: Cannot be purged // pml_EMS?: Same as pml_Locked, but if in EMS, use the physical page // specified when returning the address. For sound stuff. // void PM_SetPageLock(int pagenum,PMLockType lock) { if (pagenum < PMSoundStart) Quit("PM_SetPageLock: Locking/unlocking non-sound page"); PMPages[pagenum].locked = lock; } // // PM_Preload() - Loads as many pages as possible into all types of memory. // Calls the update function after each load, indicating the current // page, and the total pages that need to be loaded (for thermometer). // void PM_Preload(boolean (*update)(word current,word total)) { int i,j, page,oogypage; word current,total, totalnonxms,totalxms, mainfree,maintotal, emsfree,emstotal, xmsfree,xmstotal; memptr addr; PageListStruct far *p; mainfree = (MainPagesAvail - MainPagesUsed) + (EMSPagesAvail - EMSPagesUsed); xmsfree = (XMSPagesAvail - XMSPagesUsed); xmstotal = maintotal = 0; for (i = 0;i < ChunksInFile;i++) { if (!PMPages[i].offset) continue; // sparse if ( PMPages[i].emsPage != -1 || PMPages[i].mainPage != -1 ) continue; // already in main mem if ( mainfree ) { maintotal++; mainfree--; } else if ( xmsfree && (PMPages[i].xmsPage == -1) ) { xmstotal++; xmsfree--; } } total = maintotal + xmstotal; if (!total) return; page = 0; current = 0; // // cache main/ems blocks // while (maintotal) { while ( !PMPages[page].offset || PMPages[page].mainPage != -1 || PMPages[page].emsPage != -1 ) page++; if (page >= ChunksInFile) Quit ("PM_Preload: Pages>=ChunksInFile"); PM_GetPage(page); page++; current++; maintotal--; update(current,total); } // // load stuff to XMS // if (xmstotal) { for (oogypage = 0 ; PMPages[oogypage].mainPage == -1 ; oogypage++) ; addr = PM_GetPage(oogypage); if (!addr) Quit("PM_Preload: XMS buffer failed"); while (xmstotal) { while ( !PMPages[page].offset || PMPages[page].xmsPage != -1 ) page++; if (page >= ChunksInFile) Quit ("PM_Preload: Pages>=ChunksInFile"); p = &PMPages[page]; p->xmsPage = XMSPagesUsed++; if (XMSPagesUsed > XMSPagesAvail) Quit("PM_Preload: Exceeded XMS pages"); if (p->length > PMPageSize) Quit("PM_Preload: Page too long"); PML_ReadFromFile((byte far *)addr,p->offset,p->length); PML_CopyToXMS((byte far *)addr,p->xmsPage,p->length); page++; current++; xmstotal--; update(current,total); } p = &PMPages[oogypage]; PML_ReadFromFile((byte far *)addr,p->offset,p->length); } update(total,total); } ///////////////////////////////////////////////////////////////////////////// // // General code // ///////////////////////////////////////////////////////////////////////////// // // PM_NextFrame() - Increments the frame counter and adjusts the thrash // avoidence variables // // If currently in panic mode (to avoid thrashing), check to see if the // appropriate number of frames have passed since the last time that // we would have thrashed. If so, take us out of panic mode. // // void PM_NextFrame(void) { int i; // Frame count overrun - kill the LRU hit entries & reset frame count if (++PMFrameCount >= MAXLONG - 4) { for (i = 0;i < PMNumBlocks;i++) PMPages[i].lastHit = 0; PMFrameCount = 0; } #if 0 for (i = 0;i < PMSoundStart;i++) { if (PMPages[i].locked) { char buf[40]; sprintf(buf,"PM_NextFrame: Page %d is locked",i); Quit(buf); } } #endif if (PMPanicMode) { // DEBUG - set border color if ((!PMThrashing) && (!--PMPanicMode)) { // DEBUG - reset border color } } if (PMThrashing >= PMThrashThreshold) PMPanicMode = PMUnThrashThreshold; PMThrashing = false; } // // PM_Reset() - Sets up caching structures // void PM_Reset(void) { int i; PageListStruct far *page; XMSPagesAvail = XMSAvail / PMPageSizeKB; EMSPagesAvail = EMSAvail * (EMSPageSizeKB / PMPageSizeKB); EMSPhysicalPage = 0; MainPagesUsed = EMSPagesUsed = XMSPagesUsed = 0; PMPanicMode = false; // Initialize page list for (i = 0,page = PMPages;i < PMNumBlocks;i++,page++) { page->mainPage = -1; page->emsPage = -1; page->xmsPage = -1; page->locked = false; } } // // PM_Startup() - Start up the Page Mgr // void PM_Startup(void) { boolean nomain,noems,noxms; int i; if (PMStarted) return; nomain = noems = noxms = false; for (i = 1;i < _argc;i++) { switch (US_CheckParm(_argv[i],ParmStrings)) { case 0: nomain = true; break; case 1: noems = true; break; case 2: noxms = true; break; } } PML_OpenPageFile(); if (!noems) PML_StartupEMS(); if (!noxms) PML_StartupXMS(); if (nomain && !EMSPresent) Quit("PM_Startup: No main or EMS"); else PML_StartupMainMem(); PM_Reset(); PMStarted = true; } // // PM_Shutdown() - Shut down the Page Mgr // void PM_Shutdown(void) { PML_ShutdownXMS(); PML_ShutdownEMS(); if (!PMStarted) return; PML_ClosePageFile(); PML_ShutdownMainMem(); }