static MDL * BalloonAllocatePagesForMdl( IN ULONG Count ) { LARGE_INTEGER LowAddress; LARGE_INTEGER HighAddress; LARGE_INTEGER SkipBytes; SIZE_T TotalBytes; MDL *Mdl; XM_ASSERT(AllocatorInitialized); LowAddress.QuadPart = 0ull; HighAddress.QuadPart = ~0ull; SkipBytes.QuadPart = 0ull; TotalBytes = (SIZE_T)Count << PAGE_SHIFT; if (__MmAllocatePagesForMdlEx != NULL) Mdl = __MmAllocatePagesForMdlEx(LowAddress, HighAddress, SkipBytes, TotalBytes, MmCached, MM_DONT_ZERO_ALLOCATION); else Mdl = MmAllocatePagesForMdl(LowAddress, HighAddress, SkipBytes, TotalBytes); if (Mdl == NULL) goto done; XM_ASSERT((Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_PARTIAL_HAS_BEEN_MAPPED | MDL_PARTIAL | MDL_PARENT_MAPPED_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL | MDL_IO_SPACE)) == 0); done: return Mdl; }
DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable) { AssertMsgReturn(cb <= _1G, ("%#x\n", cb), VERR_OUT_OF_RANGE); /* for safe size_t -> ULONG */ /* * Try see if we get lucky first... * (We could probably just assume we're lucky on NT4.) */ int rc = rtR0MemObjNativeAllocPage(ppMem, cb, fExecutable); if (RT_SUCCESS(rc)) { size_t iPage = cb >> PAGE_SHIFT; while (iPage-- > 0) if (rtR0MemObjNativeGetPagePhysAddr(*ppMem, iPage) >= _4G) { rc = VERR_NO_LOW_MEMORY; break; } if (RT_SUCCESS(rc)) return rc; /* The following ASSUMES that rtR0MemObjNativeAllocPage returns a completed object. */ RTR0MemObjFree(*ppMem, false); *ppMem = NULL; } #ifndef IPRT_TARGET_NT4 /* * Use MmAllocatePagesForMdl to specify the range of physical addresses we wish to use. */ PHYSICAL_ADDRESS Zero; Zero.QuadPart = 0; PHYSICAL_ADDRESS HighAddr; HighAddr.QuadPart = _4G - 1; PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, cb); if (pMdl) { if (MmGetMdlByteCount(pMdl) >= cb) { __try { void *pv = MmMapLockedPagesSpecifyCache(pMdl, KernelMode, MmCached, NULL /* no base address */, FALSE /* no bug check on failure */, NormalPagePriority); if (pv) { PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_LOW, pv, cb); if (pMemNt) { pMemNt->fAllocatedPagesForMdl = true; pMemNt->cMdls = 1; pMemNt->apMdls[0] = pMdl; *ppMem = &pMemNt->Core; return VINF_SUCCESS; } MmUnmapLockedPages(pv, pMdl); } } __except(EXCEPTION_EXECUTE_HANDLER) { NTSTATUS rcNt = GetExceptionCode(); Log(("rtR0MemObjNativeAllocLow: Exception Code %#x\n", rcNt)); /* nothing */ } } MmFreePagesFromMdl(pMdl); ExFreePool(pMdl); }
/// <summary> /// System worker thread that performs actual mapping /// </summary> /// <param name="pArg">Path to the driver - PUNICODE_STRING type</param> /// <returns>Status code</returns> NTSTATUS BBMapWorker( IN PVOID pArg ) { NTSTATUS status = STATUS_SUCCESS; HANDLE hFile = NULL; PUNICODE_STRING pPath = (PUNICODE_STRING)pArg; OBJECT_ATTRIBUTES obAttr = { 0 }; IO_STATUS_BLOCK statusBlock = { 0 }; PVOID fileData = NULL; PIMAGE_NT_HEADERS pNTHeader = NULL; PVOID imageSection = NULL; PMDL pMDL = NULL; FILE_STANDARD_INFORMATION fileInfo = { 0 }; InitializeObjectAttributes( &obAttr, pPath, OBJ_KERNEL_HANDLE, NULL, NULL ); // Open driver file status = ZwCreateFile( &hFile, FILE_READ_DATA | SYNCHRONIZE, &obAttr, &statusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); if (!NT_SUCCESS( status )) { DPRINT( "BlackBone: %s: Failed to open '%wZ'. Status: 0x%X\n", __FUNCTION__, pPath, status ); return status; } // Allocate memory for file contents status = ZwQueryInformationFile( hFile, &statusBlock, &fileInfo, sizeof( fileInfo ), FileStandardInformation ); if (NT_SUCCESS( status )) fileData = ExAllocatePoolWithTag( PagedPool, fileInfo.EndOfFile.QuadPart, BB_POOL_TAG ); else DPRINT( "BlackBone: %s: Failed to get '%wZ' size. Status: 0x%X\n", __FUNCTION__, pPath, status ); // Get file contents status = ZwReadFile( hFile, NULL, NULL, NULL, &statusBlock, fileData, fileInfo.EndOfFile.LowPart, NULL, NULL ); if (NT_SUCCESS( status )) { pNTHeader = RtlImageNtHeader( fileData ); if (!pNTHeader) { DPRINT( "BlackBone: %s: Failed to obtaint NT Header for '%wZ'\n", __FUNCTION__, pPath ); status = STATUS_INVALID_IMAGE_FORMAT; } } else DPRINT( "BlackBone: %s: Failed to read '%wZ'. Status: 0x%X\n", __FUNCTION__, pPath, status ); ZwClose( hFile ); __try { if (NT_SUCCESS( status )) { // // Allocate memory from System PTEs // PHYSICAL_ADDRESS start = { 0 }, end = { 0 }; end.QuadPart = MAXULONG64; pMDL = MmAllocatePagesForMdl( start, end, start, pNTHeader->OptionalHeader.SizeOfImage ); imageSection = MmGetSystemAddressForMdlSafe( pMDL, NormalPagePriority ); if (NT_SUCCESS( status ) && imageSection) { // Copy header RtlCopyMemory( imageSection, fileData, pNTHeader->OptionalHeader.SizeOfHeaders ); // Copy sections for (PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)(pNTHeader + 1); pSection < (PIMAGE_SECTION_HEADER)(pNTHeader + 1) + pNTHeader->FileHeader.NumberOfSections; pSection++) { RtlCopyMemory( (PUCHAR)imageSection + pSection->VirtualAddress, (PUCHAR)fileData + pSection->PointerToRawData, pSection->SizeOfRawData ); } // Relocate image status = LdrRelocateImage( imageSection, STATUS_SUCCESS, STATUS_CONFLICTING_ADDRESSES, STATUS_INVALID_IMAGE_FORMAT ); if (!NT_SUCCESS( status )) DPRINT( "BlackBone: %s: Failed to relocate image '%wZ'. Status: 0x%X\n", __FUNCTION__, pPath, status ); // Fill IAT if (NT_SUCCESS( status )) status = BBResolveImageRefs( imageSection, TRUE, NULL, FALSE, NULL, 0 ); } else { DPRINT( "BlackBone: %s: Failed to allocate memory for image '%wZ'\n", __FUNCTION__, pPath ); status = STATUS_MEMORY_NOT_ALLOCATED; } } // Call entrypoint if (NT_SUCCESS( status ) && pNTHeader->OptionalHeader.AddressOfEntryPoint) { PDRIVER_INITIALIZE pEntryPoint = (PDRIVER_INITIALIZE)((ULONG_PTR)imageSection + pNTHeader->OptionalHeader.AddressOfEntryPoint); pEntryPoint( NULL, NULL ); } // Wipe header if (NT_SUCCESS( status ) && imageSection) RtlZeroMemory( imageSection, pNTHeader->OptionalHeader.SizeOfHeaders ); } __except (EXCEPTION_EXECUTE_HANDLER) { DPRINT( "BlackBone: %s: Exception: 0x%X \n", __FUNCTION__, GetExceptionCode() ); } // Erase info about allocated region if (pMDL) { // Free image memory in case of failure if(!NT_SUCCESS( status )) MmFreePagesFromMdl( pMDL ); ExFreePool( pMDL ); } if (fileData) ExFreePoolWithTag( fileData, BB_POOL_TAG ); if (NT_SUCCESS( status )) DPRINT( "BlackBone: %s: Successfully mapped '%wZ' at 0x%p\n", __FUNCTION__, pPath, imageSection ); return status; }
VOID BalloonFill( IN WDFOBJECT WdfDevice, IN size_t num) { PMDL pPageMdl; PHYSICAL_ADDRESS LowAddress; PHYSICAL_ADDRESS HighAddress; PPAGE_LIST_ENTRY pNewPageListEntry; PDEVICE_CONTEXT devCtx = GetDeviceContext(WdfDevice); ULONG pages_per_request = PAGE_SIZE/sizeof(PFN_NUMBER); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__); LowAddress.QuadPart = 0; HighAddress.QuadPart = (ULONGLONG)-1; num = min(num, pages_per_request); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> BalloonFill num = %d\n", num); for (devCtx->num_pfns = 0; devCtx->num_pfns < num; devCtx->num_pfns++) { if(IsLowMemory(WdfDevice)) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "LowMemoryCondition event was set to signaled,allocations stops, BalPageCount=%d\n", devCtx->num_pages); break; } pPageMdl = MmAllocatePagesForMdl( LowAddress, HighAddress, LowAddress, PAGE_SIZE ); if (pPageMdl == NULL) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "Balloon MDL Page Allocation Failed!!!, BalPageCount=%d\n", devCtx->num_pages); break; } if (MmGetMdlByteCount(pPageMdl) != PAGE_SIZE) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "Balloon MDL Page Allocation < PAGE_SIZE =%d, Failed!!!, BalPageCount=%d\n",MmGetMdlByteCount(pPageMdl), devCtx->num_pages); MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); break; } pNewPageListEntry = (PPAGE_LIST_ENTRY)ExAllocateFromNPagedLookasideList(&devCtx->LookAsideList); if (pNewPageListEntry == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "List Entry Allocation Failed!!!\n"); MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); break; } pNewPageListEntry->PageMdl = pPageMdl; pNewPageListEntry->PagePfn = devCtx->pfns_table[devCtx->num_pfns] = *MmGetMdlPfnArray(pPageMdl); PushEntryList(&devCtx->PageListHead, &(pNewPageListEntry->SingleListEntry)); devCtx->num_pages++; } if (devCtx->num_pfns > 0) { BalloonTellHost(WdfDevice, devCtx->InfVirtQueue); } }
VOID BalloonFill( IN WDFOBJECT WdfDevice, IN size_t num) { PDEVICE_CONTEXT ctx = GetDeviceContext(WdfDevice); PHYSICAL_ADDRESS LowAddress; PHYSICAL_ADDRESS HighAddress; PHYSICAL_ADDRESS SkipBytes; PPAGE_LIST_ENTRY pNewPageListEntry; PMDL pPageMdl; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__); ctx->num_pfns = 0; if (IsLowMemory(WdfDevice)) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "Low memory. Allocated pages: %d\n", ctx->num_pages); return; } num = min(num, PAGE_SIZE / sizeof(PFN_NUMBER)); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "Inflate balloon with %d pages.\n", num); LowAddress.QuadPart = 0; HighAddress.QuadPart = (ULONGLONG)-1; SkipBytes.QuadPart = 0; #if (NTDDI_VERSION < NTDDI_WS03SP1) pPageMdl = MmAllocatePagesForMdl(LowAddress, HighAddress, SkipBytes, num * PAGE_SIZE); #else pPageMdl = MmAllocatePagesForMdlEx(LowAddress, HighAddress, SkipBytes, num * PAGE_SIZE, MmNonCached, MM_DONT_ZERO_ALLOCATION); #endif if (pPageMdl == NULL) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "Failed to allocate pages.\n"); return; } if (MmGetMdlByteCount(pPageMdl) != (num * PAGE_SIZE)) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "Not all requested memory was allocated (%d/%d).\n", MmGetMdlByteCount(pPageMdl), num * PAGE_SIZE); MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); return; } pNewPageListEntry = (PPAGE_LIST_ENTRY)ExAllocateFromNPagedLookasideList( &ctx->LookAsideList); if (pNewPageListEntry == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "Failed to allocate list entry.\n"); MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); return; } pNewPageListEntry->PageMdl = pPageMdl; PushEntryList(&ctx->PageListHead, &(pNewPageListEntry->SingleListEntry)); ctx->num_pfns = num; ctx->num_pages += ctx->num_pfns; RtlCopyMemory(ctx->pfns_table, MmGetMdlPfnArray(pPageMdl), ctx->num_pfns * sizeof(PFN_NUMBER)); BalloonTellHost(WdfDevice, ctx->InfVirtQueue); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__); }
NTSTATUS AWEAllocSetSize(IN POBJECT_CONTEXT Context, IN OUT PIO_STATUS_BLOCK IoStatus, IN PLARGE_INTEGER EndOfFile) { PAGED_CODE(); KdPrint(("AWEAlloc: Setting size to %u MB.\n", (ULONG)(EndOfFile->QuadPart >> 20))); if (EndOfFile->QuadPart == 0) { Context->VirtualSize = EndOfFile->QuadPart; IoStatus->Status = STATUS_SUCCESS; IoStatus->Information = 0; return STATUS_SUCCESS; } for (;;) { PBLOCK_DESCRIPTOR block; SIZE_T bytes_to_allocate; if (Context->TotalSize >= EndOfFile->QuadPart) { Context->VirtualSize = EndOfFile->QuadPart; IoStatus->Status = STATUS_SUCCESS; IoStatus->Information = 0; return STATUS_SUCCESS; } block = ExAllocatePoolWithTag(NonPagedPool, sizeof(BLOCK_DESCRIPTOR), POOL_TAG); if (block == NULL) { IoStatus->Status = STATUS_NO_MEMORY; IoStatus->Information = 0; return STATUS_NO_MEMORY; } RtlZeroMemory(block, sizeof(BLOCK_DESCRIPTOR)); if ((EndOfFile->QuadPart - Context->TotalSize) > MAX_BLOCK_SIZE) bytes_to_allocate = MAX_BLOCK_SIZE; else bytes_to_allocate = (SIZE_T) AWEAllocGetRequiredPagesForSize(EndOfFile->QuadPart - Context->TotalSize); KdPrint(("AWEAlloc: Allocating %u MB.\n", (ULONG)(bytes_to_allocate >> 20))); #ifndef _WIN64 // On 32-bit, first try to allocate as high as possible KdPrint(("AWEAlloc: Allocating above 8 GB.\n")); block->Mdl = MmAllocatePagesForMdl(physical_address_8GB, physical_address_max64, physical_address_zero, bytes_to_allocate); if (AWEAllocAddBlock(Context, block)) continue; KdPrint(("AWEAlloc: Not enough memory available above 8 GB.\n" "AWEAlloc: Allocating above 6 GB.\n")); AWEAllocLogError(AWEAllocDriverObject, 0, 0, NULL, 0, 1000, AWEALLOC_STATUS_ALLOCATION_LOW_MEMORY, 101, STATUS_INSUFFICIENT_RESOURCES, 0, 0, NULL, L"Error allocating above 8 GB."); block->Mdl = MmAllocatePagesForMdl(physical_address_6GB, physical_address_max64, physical_address_zero, bytes_to_allocate); if (AWEAllocAddBlock(Context, block)) continue; KdPrint(("AWEAlloc: Not enough memory available above 6 GB.\n" "AWEAlloc: Allocating above 5 GB.\n")); AWEAllocLogError(AWEAllocDriverObject, 0, 0, NULL, 0, 1000, AWEALLOC_STATUS_ALLOCATION_LOW_MEMORY, 101, STATUS_INSUFFICIENT_RESOURCES, 0, 0, NULL, L"Error allocating above 6 GB."); block->Mdl = MmAllocatePagesForMdl(physical_address_5GB, physical_address_max64, physical_address_zero, bytes_to_allocate); if (AWEAllocAddBlock(Context, block)) continue; KdPrint(("AWEAlloc: Not enough memory available above 5 GB.\n" "AWEAlloc: Allocating above 4 GB.\n")); AWEAllocLogError(AWEAllocDriverObject, 0, 0, NULL, 0, 1000, AWEALLOC_STATUS_ALLOCATION_LOW_MEMORY, 101, STATUS_INSUFFICIENT_RESOURCES, 0, 0, NULL, L"Error allocating above 5 GB."); block->Mdl = MmAllocatePagesForMdl(physical_address_4GB, physical_address_max64, physical_address_zero, bytes_to_allocate); if (AWEAllocAddBlock(Context, block)) continue; KdPrint(("AWEAlloc: Not enough memory available above 4 GB.\n" "AWEAlloc: Allocating at any available location.\n")); AWEAllocLogError(AWEAllocDriverObject, 0, 0, NULL, 0, 1000, AWEALLOC_STATUS_ALLOCATION_LOW_MEMORY, 101, STATUS_INSUFFICIENT_RESOURCES, 0, 0, NULL, L"Error allocating above 4 GB."); #endif // !_WIN64 block->Mdl = MmAllocatePagesForMdl(physical_address_zero, physical_address_max64, physical_address_zero, bytes_to_allocate); if (AWEAllocAddBlock(Context, block)) continue; KdPrint(("AWEAlloc: MmAllocatePagesForMdl failed.\n")); AWEAllocLogError(AWEAllocDriverObject, 0, 0, NULL, 0, 1000, STATUS_NO_MEMORY, 101, STATUS_NO_MEMORY, 0, 0, NULL, L"Error allocating physical memory."); ExFreePoolWithTag(block, POOL_TAG); IoStatus->Status = STATUS_NO_MEMORY; IoStatus->Information = 0; return STATUS_NO_MEMORY; } }