/*++ Copyright (c) 1999 Microsoft Corporation Module Name: util.c Author: ervinp Environment: Kernel mode Revision History: --*/ #include #include #include #include #include "usb8023.h" #include "debug.h" #if DBG_WRAP_MEMORY /* * Memory Allocation: * To catch memory leaks, we will keep a count and list of all allocated memory * and then assert that the memory is all freed when we exit. */ ULONG dbgTotalMemCount = 0; LIST_ENTRY dbgAllMemoryList; #define ALIGNBYTES 32 struct memHeader { PUCHAR actualPtr; ULONG actualSize; LIST_ENTRY listEntry; }; #endif PVOID AllocPool(ULONG size) /* * * Return a 32-byte aligned pointer. * Place a guard word at the end of the buffer. * Cache the actual allocated pointer and size before the returned pointer. * */ { PUCHAR resultPtr; #if DBG_WRAP_MEMORY { PUCHAR actualPtr = ExAllocatePoolWithTag( NonPagedPool, size+ALIGNBYTES+sizeof(struct memHeader)+sizeof(ULONG), DRIVER_SIG); if (actualPtr){ struct memHeader *memHdr; KIRQL oldIrql; RtlZeroMemory(actualPtr, size+32+sizeof(struct memHeader)); *(PULONG)(actualPtr+size+ALIGNBYTES+sizeof(struct memHeader)) = GUARD_WORD; /* * ExAllocatePoolWithTag returns the 32-byte aligned pointer * from ExAllocatePool plus 8 bytes for the tag and kernel tracking info * (but don't depend on this). * Align the pointer we return, and cache away the actual pointer to free and * the buffer size. */ // ASSERT(((ULONG_PTR)actualPtr & 0x1F) == 0x08); NT only resultPtr = (PUCHAR)((ULONG_PTR)(actualPtr+ALIGNBYTES+sizeof(struct memHeader)) & ~(ALIGNBYTES-1)); memHdr = (struct memHeader *)(resultPtr-sizeof(struct memHeader)); memHdr->actualPtr = actualPtr; memHdr->actualSize = size+ALIGNBYTES+sizeof(struct memHeader)+sizeof(ULONG); dbgTotalMemCount += memHdr->actualSize; KeAcquireSpinLock(&globalSpinLock, &oldIrql); InsertTailList(&dbgAllMemoryList, &memHdr->listEntry); KeReleaseSpinLock(&globalSpinLock, oldIrql); } else { resultPtr = NULL; } } #else resultPtr = ExAllocatePoolWithTag(NonPagedPool, size, DRIVER_SIG); if (resultPtr){ RtlZeroMemory(resultPtr, size); } #endif return resultPtr; } VOID FreePool(PVOID ptr) { #if DBG_WRAP_MEMORY { KIRQL oldIrql; struct memHeader *memHdr; ASSERT(ptr); memHdr = (struct memHeader *)((PUCHAR)ptr - sizeof(struct memHeader)); ASSERT(*(PULONG)(memHdr->actualPtr+memHdr->actualSize-sizeof(ULONG)) == GUARD_WORD); ASSERT(dbgTotalMemCount >= memHdr->actualSize); KeAcquireSpinLock(&globalSpinLock, &oldIrql); ASSERT(!IsListEmpty(&dbgAllMemoryList)); RemoveEntryList(&memHdr->listEntry); KeReleaseSpinLock(&globalSpinLock, oldIrql); dbgTotalMemCount -= memHdr->actualSize; ExFreePool(memHdr->actualPtr); } #else ExFreePool(ptr); #endif } /* ******************************************************************************** * MemDup ******************************************************************************** * * Return a fresh copy of the argument. * */ PVOID MemDup(PVOID dataPtr, ULONG length) { PVOID newPtr; newPtr = (PVOID)AllocPool(length); if (newPtr){ RtlCopyMemory(newPtr, dataPtr, length); } ASSERT(newPtr); return newPtr; } VOID DelayMs(ULONG numMillisec) { LARGE_INTEGER deltaTime; /* * Get delay time into relative units of 100 nsec. */ deltaTime.QuadPart = -10000 * numMillisec; KeDelayExecutionThread(KernelMode, FALSE, &deltaTime); } /* * AllocateCommonResources * * Allocate adapter resources that are common to RNDIS and NDIS interfaces * but which for some reason can't be allocated by NewAdapter(). * These resources will be freed by FreeAdapter(). */ BOOLEAN AllocateCommonResources(ADAPTEREXT *adapter) { BOOLEAN result = TRUE; ULONG i; /* * Build the packet pool for this adapter. */ for (i = 0; i < USB_PACKET_POOL_SIZE; i++){ USBPACKET *packet = NewPacket(adapter); if (packet){ EnqueueFreePacket(packet); } else { ASSERT(packet); result = FALSE; break; } } ASSERT(result); return result; } BOOLEAN GetRegValue(ADAPTEREXT *adapter, PWCHAR wValueName, OUT PULONG valuePtr, BOOLEAN hwKey) { BOOLEAN success = FALSE; NTSTATUS status; HANDLE hRegDevice; KIRQL oldIrql; *valuePtr = 0; status = IoOpenDeviceRegistryKey( adapter->physDevObj, hwKey ? PLUGPLAY_REGKEY_DEVICE : PLUGPLAY_REGKEY_DRIVER, KEY_READ, &hRegDevice); if (NT_SUCCESS(status)){ UNICODE_STRING uValueName; PKEY_VALUE_FULL_INFORMATION keyValueInfo; ULONG keyValueTotalSize, actualLength; RtlInitUnicodeString(&uValueName, wValueName); keyValueTotalSize = sizeof(KEY_VALUE_FULL_INFORMATION) + uValueName.Length*sizeof(WCHAR) + sizeof(ULONG); keyValueInfo = AllocPool(keyValueTotalSize); if (keyValueInfo){ status = ZwQueryValueKey( hRegDevice, &uValueName, KeyValueFullInformation, keyValueInfo, keyValueTotalSize, &actualLength); if (NT_SUCCESS(status)){ ASSERT(keyValueInfo->Type == REG_DWORD); ASSERT(keyValueInfo->DataLength == sizeof(ULONG)); *valuePtr = *((PULONG)(((PCHAR)keyValueInfo)+keyValueInfo->DataOffset)); success = TRUE; } FreePool(keyValueInfo); } else { ASSERT(keyValueInfo); } ZwClose(hRegDevice); } else { DBGWARN(("IoOpenDeviceRegistryKey failed with %xh.", status)); } return success; } BOOLEAN SetRegValue(ADAPTEREXT *adapter, PWCHAR wValueName, ULONG newValue, BOOLEAN hwKey) { BOOLEAN success = FALSE; NTSTATUS status; HANDLE hRegDevice; KIRQL oldIrql; status = IoOpenDeviceRegistryKey( adapter->physDevObj, hwKey ? PLUGPLAY_REGKEY_DEVICE : PLUGPLAY_REGKEY_DRIVER, KEY_READ, &hRegDevice); if (NT_SUCCESS(status)){ UNICODE_STRING uValueName; PKEY_VALUE_FULL_INFORMATION keyValueInfo; ULONG keyValueTotalSize, actualLength; RtlInitUnicodeString(&uValueName, wValueName); keyValueTotalSize = sizeof(KEY_VALUE_FULL_INFORMATION) + uValueName.Length*sizeof(WCHAR) + sizeof(ULONG); keyValueInfo = AllocPool(keyValueTotalSize); if (keyValueInfo){ status = ZwSetValueKey( hRegDevice, &uValueName, 0, REG_DWORD, &newValue, sizeof(ULONG)); if (NT_SUCCESS(status)){ success = TRUE; } else { DBGERR(("SetRegValue: ZwSetValueKey failed with %xh.", status)); } FreePool(keyValueInfo); } else { ASSERT(keyValueInfo); } ZwClose(hRegDevice); } else { DBGOUT(("IoOpenDeviceRegistryKey failed with %xh.", status)); } return success; } /* * MyInitializeMdl * * Wrapper for MmInitializeMdl, which doesn't compile under NDIS headers. */ VOID MyInitializeMdl(PMDL mdl, PVOID buf, ULONG bufLen) { MmInitializeMdl(mdl, buf, bufLen); MmBuildMdlForNonPagedPool(mdl); } PVOID GetSystemAddressForMdlSafe(PMDL MdlAddress) { PVOID buf; /* * Note: we could use MmGetSystemAddressSafe here * but not for Win98SE */ if (MdlAddress){ CSHORT oldFlags = MdlAddress->MdlFlags; MdlAddress->MdlFlags |= MDL_MAPPING_CAN_FAIL; #if defined(SPECIAL_WIN98SE_BUILD) || defined(SPECIAL_WINME_BUILD) buf = MmGetSystemAddressForMdl(MdlAddress); #else buf = MmGetSystemAddressForMdlSafe(MdlAddress, NormalPoolPriority); #endif MdlAddress->MdlFlags &= (oldFlags | ~MDL_MAPPING_CAN_FAIL); } else { ASSERT(MdlAddress); buf = NULL; } return buf; } ULONG CopyMdlToBuffer(PUCHAR buf, PMDL mdl, ULONG bufLen) { ULONG totalLen = 0; while (mdl){ ULONG thisBufLen = MmGetMdlByteCount(mdl); if (totalLen+thisBufLen <= bufLen){ PVOID thisBuf = GetSystemAddressForMdlSafe(mdl); if (thisBuf){ RtlCopyMemory(buf+totalLen, thisBuf, thisBufLen); totalLen += thisBufLen; mdl = mdl->Next; } else { break; } } else { DBGERR(("CopyMdlToBuffer: mdl @ %ph is too large for buffer size %xh.", mdl, bufLen)); break; } } return totalLen; } ULONG GetMdlListTotalByteCount(PMDL mdl) { ULONG totalBytes = 0; do { totalBytes += MmGetMdlByteCount(mdl); mdl = mdl->Next; } while (mdl); return totalBytes; } VOID ByteSwap(PUCHAR buf, ULONG len) { while (len >= 2){ UCHAR tmp = buf[0]; buf[0] = buf[1]; buf[1] = tmp; buf += 2; len -= 2; } } #if SPECIAL_WIN98SE_BUILD PIO_WORKITEM MyIoAllocateWorkItem(PDEVICE_OBJECT DeviceObject) { PIO_WORKITEM ioWorkItem; PWORK_QUEUE_ITEM exWorkItem; ioWorkItem = ExAllocatePool(NonPagedPool, sizeof(IO_WORKITEM)); if (ioWorkItem) { ioWorkItem->DeviceObject = DeviceObject; exWorkItem = &ioWorkItem->WorkItem; #if DBG ioWorkItem->Size = sizeof(IO_WORKITEM); #endif ExInitializeWorkItem(exWorkItem, MyIopProcessWorkItem, ioWorkItem); } return ioWorkItem; } VOID MyIoFreeWorkItem(PIO_WORKITEM IoWorkItem) { ASSERT(IoWorkItem->Size == sizeof(IO_WORKITEM)); ExFreePool( IoWorkItem ); } VOID MyIoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context) { PWORK_QUEUE_ITEM exWorkItem; ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); ASSERT(IoWorkItem->Size == sizeof(IO_WORKITEM)); ObReferenceObject( IoWorkItem->DeviceObject ); IoWorkItem->Routine = WorkerRoutine; IoWorkItem->Context = Context; exWorkItem = &IoWorkItem->WorkItem; ExQueueWorkItem( exWorkItem, QueueType ); } VOID MyIopProcessWorkItem(IN PVOID Parameter) { PIO_WORKITEM ioWorkItem; PDEVICE_OBJECT deviceObject; PAGED_CODE(); ioWorkItem = (PIO_WORKITEM)Parameter; deviceObject = ioWorkItem->DeviceObject; ioWorkItem->Routine(deviceObject, ioWorkItem->Context); ObDereferenceObject(deviceObject); } #endif