windows-nt/Source/XPSP1/NT/base/mvdm/xms.486/xmsumb.c
2020-09-26 16:20:57 +08:00

243 lines
6.1 KiB
C

/*++
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 <xms.h>
#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);
}
}