/*++ Copyright (c) 1992 Microsoft Corporation Module Name: XNSUMB.C Abstract: Routines to service XMS Request UMB and Release UMB functions. Also includes UMB initialization routine Author: William Hsieh (williamh) Created 23-Sept-1992 [Environment:] User mode, running in the MVDM context (bop from 16bits) [Notes:] Revision History: --*/ #include #include "umb.h" #include "softpc.h" // This global variable points to the first node(lowest address) UMB list static PXMSUMB xmsUMBHead; static BOOL xmsIsON = FALSE; // ------------------------------------------------------------------ // Initialization for UMB support. It create a single direction linked // list and allocate all available UMBs. // Input: client (AX:BX) = segment:offset of himem.sys A20State variable // // Output: list header, xmsUMBHead set. //------------------------------------------------------------------- VOID xmsInitUMB(VOID) { PVOID Address; ULONG Size; PXMSUMB xmsUMB, xmsUMBNew; xmsUMBHead = NULL; while (ReserveUMB(UMB_OWNER_XMS, &Address, &Size) && (xmsUMBNew = (PXMSUMB) malloc(sizeof(XMSUMB))) != NULL) { // convert size in bytes to paragraphs xmsUMBNew->Size = (WORD) (Size >> 4); // convert linear address to paragraphs segment xmsUMBNew->Segment = (WORD)((DWORD)Address >> 4); xmsUMBNew->Owner = 0; if (xmsUMBHead == NULL) { xmsUMBHead = xmsUMBNew; xmsUMBHead->Next = NULL; } else { xmsUMBNew->Next = xmsUMB->Next; xmsUMB->Next = xmsUMBNew; } xmsUMB = xmsUMBNew; } xmsIsON = TRUE; pHimemA20State = (PBYTE) GetVDMAddr(getAX(), getBX()); xmsEnableA20Wrapping(); } // This function receives control whenever there has been an UMB released // Input: PVOID Address = the block address // ULONG Size = the block size VOID xmsReleaseUMBNotify( PVOID Address, DWORD Size ) { // If the block is good and xms driver is ON, // grab the block and insert it into our xms UMB list if (Address != NULL && Size > 0 && xmsIsON && ReserveUMB(UMB_OWNER_XMS, &Address, &Size)){ xmsInsertUMB(Address, Size); } } // ------------------------------------------------------------------ // Insert a given UMB into the list // Input: PVOID Address = linear address of the block to be inserted // ULONG Size = size in byte of the block // Output: TRUE if the block was inserted to the list successfully // FALSE if the block wasn't inserted //------------------------------------------------------------------- VOID xmsInsertUMB( PVOID Address, ULONG Size ) { PXMSUMB xmsUMB, xmsUMBNew; WORD Segment; Segment = (WORD) ((DWORD)Address >> 4); Size >>= 4; xmsUMB = xmsUMBNew = xmsUMBHead; while (xmsUMBNew != NULL && xmsUMBNew->Segment < Segment) { xmsUMB = xmsUMBNew; xmsUMBNew = xmsUMBNew->Next; } // merge it with previous block if possible if (xmsUMB != NULL && xmsUMB->Owner == 0 && Segment == xmsUMB->Segment + xmsUMB->Size) { xmsUMB->Size += (WORD) Size; return; } // merge it with the after block if possible if (xmsUMBNew != NULL && xmsUMBNew->Owner == 0 && xmsUMBNew->Segment == Segment + Size) { xmsUMBNew->Size += (WORD) Size; xmsUMBNew->Segment = Segment; return; } // create a new node for the block if ((xmsUMBNew = (PXMSUMB)malloc(sizeof(XMSUMB))) != NULL) { xmsUMBNew->Size = (WORD) Size; xmsUMBNew->Segment = Segment; xmsUMBNew->Owner = 0; if (xmsUMBHead == NULL) { xmsUMBHead = xmsUMBNew; xmsUMBNew->Next = NULL; } else { xmsUMBNew->Next = xmsUMB->Next; xmsUMB->Next = xmsUMBNew; } } } // ------------------------------------------------------------------ // XMS function 16, Request UMB. // Input: (DX) = requested size in paragraphs // Output: (AX) = 1 if succeed and // (BX) has segment address(number) of the block // (DX) has actual allocated size in paragraphs // (AX) = 0 if failed and // (BL) = 0xB0, (DX) = largest size available // or // (BL) = 0xB1 if no UMBs are available //------------------------------------------------------------------- VOID xmsRequestUMB(VOID) { PXMSUMB xmsUMB, xmsUMBNew; WORD SizeRequested, SizeLargest; xmsUMB = xmsUMBHead; SizeRequested = getDX(); SizeLargest = 0; while (xmsUMB != NULL) { if (xmsUMB->Owner == 0) { if (xmsUMB->Size >= SizeRequested) { if((xmsUMB->Size - SizeRequested) >= XMSUMB_THRESHOLD && (xmsUMBNew = (PXMSUMB) malloc(sizeof(XMSUMB))) != NULL) { xmsUMBNew->Segment = xmsUMB->Segment + SizeRequested; xmsUMBNew->Size = xmsUMB->Size - SizeRequested; xmsUMBNew->Next = xmsUMB->Next; xmsUMB->Next = xmsUMBNew; xmsUMBNew->Owner = 0; xmsUMB->Size -= xmsUMBNew->Size; } xmsUMB->Owner = 0xFFFF; setAX(1); setBX(xmsUMB->Segment); setDX(xmsUMB->Size); return; } else { if (xmsUMB->Size > SizeLargest) SizeLargest = xmsUMB->Size; } } xmsUMB = xmsUMB->Next; } setAX(0); setDX(SizeLargest); if (SizeLargest > 0) setBL(0xB0); else setBL(0xB1); } //------------------------------------------------------------------ // XMS function 17, Release UMB. // Input : (DX) = segment to be released // Output: (AX) = 1 if succeed // (AX) = 0 if failed and // (BL) = 0xB2 if segment not found in the list //------------------------------------------------------------------ VOID xmsReleaseUMB(VOID) { PXMSUMB xmsUMB, xmsUMBNext; WORD Segment; xmsUMB = xmsUMBHead; Segment = getDX(); while (xmsUMB != NULL && xmsUMB->Segment != Segment) { xmsUMB = xmsUMB->Next; } if (xmsUMB != NULL && xmsUMB->Owner != 0) { xmsUMB->Owner = 0; // no walk through the entire list to combine consecutive // blocks together xmsUMB = xmsUMBHead; while (xmsUMB != NULL) { while (xmsUMB->Owner == 0 && (xmsUMBNext = xmsUMB->Next) != NULL && xmsUMBNext->Owner == 0 && (WORD)(xmsUMB->Segment + xmsUMB->Size) == xmsUMBNext->Segment){ xmsUMB->Size += xmsUMBNext->Size; xmsUMB->Next = xmsUMBNext->Next; free(xmsUMBNext); } xmsUMB = xmsUMB->Next; } setAX(1); } else { setBL(0xB2); setAX(0); } }