static UCHAR XmsAlloc(WORD Size, PWORD Handle) { BYTE i; PXMS_HANDLE HandleEntry; DWORD CurrentIndex = 0; ULONG RunStart; ULONG RunSize; if (Size > FreeBlocks) return XMS_STATUS_OUT_OF_MEMORY; for (i = 0; i < XMS_MAX_HANDLES; i++) { HandleEntry = &HandleTable[i]; if (HandleEntry->Handle == 0) { *Handle = i + 1; break; } } if (i == XMS_MAX_HANDLES) return XMS_STATUS_OUT_OF_HANDLES; /* Optimize blocks */ for (i = 0; i < XMS_MAX_HANDLES; i++) { /* Skip free and locked blocks */ if (HandleEntry->Handle == 0 || HandleEntry->LockCount > 0) continue; CurrentIndex = (HandleEntry->Address - XMS_ADDRESS) / XMS_BLOCK_SIZE; /* Check if there is any free space before this block */ RunSize = RtlFindLastBackwardRunClear(&AllocBitmap, CurrentIndex, &RunStart); if (RunSize == 0) break; /* Move this block back */ RtlMoveMemory((PVOID)REAL_TO_PHYS(HandleEntry->Address - RunSize * XMS_BLOCK_SIZE), (PVOID)REAL_TO_PHYS(HandleEntry->Address), RunSize * XMS_BLOCK_SIZE); /* Update the address */ HandleEntry->Address -= RunSize * XMS_BLOCK_SIZE; } while (CurrentIndex < XMS_BLOCKS) { RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart); if (RunSize == 0) break; if (RunSize >= HandleEntry->Size) { /* Allocate it here */ HandleEntry->Handle = i + 1; HandleEntry->LockCount = 0; HandleEntry->Size = Size; HandleEntry->Address = XMS_ADDRESS + RunStart * XMS_BLOCK_SIZE; FreeBlocks -= Size; RtlSetBits(&AllocBitmap, RunStart, HandleEntry->Size); return XMS_STATUS_SUCCESS; } /* Keep searching */ CurrentIndex = RunStart + RunSize; } return XMS_STATUS_OUT_OF_MEMORY; }
ULONG NtdllBitmap::FindLastBackwardRunClear( ULONG from_index, PULONG starting_run_index ) { assert(RtlFindLastBackwardRunClear != NULL); return RtlFindLastBackwardRunClear(this, from_index, starting_run_index); }