int GetKPCR(struct PmemMemoryInfo *info) { __int64 active_processors = KeQueryActiveProcessors(); int i; for (i=0; i < 32; i++) { info->KPCR[i].QuadPart = 0; }; for (i=0; i < 32; i++) { if (active_processors & ((__int64)1 << i)) { KeSetSystemAffinityThread((__int64)1 << i); #if _WIN64 || __amd64__ //64 bit uses gs and _KPCR.Self is at 0x18: info->KPCR[i].QuadPart = (uintptr_t)__readgsqword(0x18); #else //32 bit uses fs and _KPCR.SelfPcr is at 0x1c: info->KPCR[i].QuadPart = (uintptr_t)__readfsword(0x1c); #endif }; }; KeRevertToUserAffinityThread(); return 1; };
RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) { #if 0 /* this isn't safe at all IRQLs (great work guys) */ KAFFINITY Mask = KeQueryActiveProcessors(); return RTCpuSetFromU64(pSet, Mask); #else *pSet = g_rtMpNtCpuSet; return pSet; #endif }
RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu) { if (idCpu >= MAXIMUM_PROCESSORS) return false; #if 0 /* this isn't safe at all IRQLs (great work guys) */ KAFFINITY Mask = KeQueryActiveProcessors(); return !!(Mask & RT_BIT_64(idCpu)); #else return RTCpuSetIsMember(&g_rtMpNtCpuSet, idCpu); #endif }
NTSTATUS DriverDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION IrpSp; ULONG IOControlCode = 0; ULONG dwBytesWritten = 0; PCHAR pInBuf = NULL, pOutBuf = NULL; unsigned int _cpu_thread_id = 0; unsigned int new_cpu_thread_id = 0; ULONG _num_active_cpus = 0; KAFFINITY _kaffinity = 0; UINT32 core_id = 0; // // Get the current IRP stack location of this request // IrpSp = IoGetCurrentIrpStackLocation (Irp); IOControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; DbgPrint( "[chipsec] >>>>>>>>>> IOCTL >>>>>>>>>>\n" ); DbgPrint( "[chipsec] DeviceObject = 0x%x IOCTL = 0x%x\n", DeviceObject, IOControlCode ); DbgPrint( "[chipsec] InputBufferLength = 0x%x, OutputBufferLength = 0x%x\n", IrpSp->Parameters.DeviceIoControl.InputBufferLength, IrpSp->Parameters.DeviceIoControl.OutputBufferLength ); // // CPU thread ID // _num_active_cpus = KeQueryActiveProcessorCount( NULL ); _kaffinity = KeQueryActiveProcessors(); _cpu_thread_id = KeGetCurrentProcessorNumber(); DbgPrint( "[chipsec] Active CPU threads : %d (KeNumberProcessors = %d)\n", _num_active_cpus, KeNumberProcessors ); DbgPrint( "[chipsec] Active CPU mask (KAFFINITY): 0x%08X\n", _kaffinity ); DbgPrint( "[chipsec] Current CPU thread : %d\n", _cpu_thread_id ); // // Switch on the IOCTL code that is being requested by the user. If the // operation is a valid one for this device do the needful. // Irp -> IoStatus.Information = 0; switch( IOControlCode ) { case READ_PCI_CFG_REGISTER: { DWORD val; BYTE size = 0; WORD bdf[4]; BYTE bus = 0, dev = 0, fun = 0, off = 0; DbgPrint( "[chipsec] > READ_PCI_CFG_REGISTER\n" ); RtlCopyBytes( bdf,Irp->AssociatedIrp.SystemBuffer, 4*sizeof(WORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 4*sizeof(WORD), sizeof(BYTE) ); bus = (UINT8)bdf[0]; dev = (UINT8)bdf[1]; fun = (UINT8)bdf[2]; off = (UINT8)bdf[3]; if( 1 != size && 2 != size && 4 != size) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } val = ReadPCICfg( bus, dev, fun, off, size ); IrpSp->Parameters.Read.Length = size; RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&val, size ); DbgPrint( "[chipsec][READ_PCI_CFG_REGISTER] B/D/F: %#04x/%#04x/%#04x, OFFSET: %#04x, value = %#010x (size = 0x%x)\n", bus, dev, fun, off, val, size ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case WRITE_PCI_CFG_REGISTER: { DWORD val = 0; WORD bdf[6]; BYTE bus = 0, dev = 0, fun = 0, off = 0; BYTE size = 0; DbgPrint( "[chipsec] > WRITE_PCI_CFG_REGISTER\n" ); RtlCopyBytes( bdf, Irp->AssociatedIrp.SystemBuffer, 6 * sizeof(WORD) ); bus = (UINT8)bdf[0]; dev = (UINT8)bdf[1]; fun = (UINT8)bdf[2]; off = (UINT8)bdf[3]; RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 6*sizeof(WORD), sizeof(BYTE) ); val = ((DWORD)bdf[5] << 16) | bdf[4]; DbgPrint( "[chipsec][WRITE_PCI_CFG_REGISTER] B/D/F: %#02x/%#02x/%#02x, OFFSET: %#02x, value = %#010x (size = %#02x)\n", bus, dev, fun, off, val, size ); WritePCICfg( bus, dev, fun, off, size, val ); Status = STATUS_SUCCESS; break; } case IOCTL_READ_PHYSMEM: { UINT32 len = 0; PVOID virt_addr; PHYSICAL_ADDRESS phys_addr = { 0x0, 0x0 }; DbgPrint( "[chipsec] > IOCTL_READ_PHYSMEM\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3*sizeof(UINT32)) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; phys_addr.HighPart = ((UINT32*)pInBuf)[0]; phys_addr.LowPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; if( !len ) len = 4; if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < len ) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } __try { Status = _read_phys_mem( phys_addr, len, pOutBuf ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: exception code 0x%X\n", Status ); break; } if( NT_SUCCESS(Status) ) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] Contents:\n" ); _dump_buffer( (unsigned char *)pOutBuf, min(len,0x100) ); dwBytesWritten = len; } break; } case IOCTL_WRITE_PHYSMEM: { UINT32 len = 0; PVOID virt_addr = 0; PHYSICAL_ADDRESS phys_addr = { 0x0, 0x0 }; DbgPrint( "[chipsec] > IOCTL_WRITE_PHYSMEM\n" ); if( Irp->AssociatedIrp.SystemBuffer ) { pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } phys_addr.HighPart = ((UINT32*)pInBuf)[0]; phys_addr.LowPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; ((UINT32*)pInBuf) += 3; if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < len + 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] Writing contents:\n" ); _dump_buffer( (unsigned char *)pInBuf, min(len,0x100) ); __try { Status = _write_phys_mem( phys_addr, len, pInBuf ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: exception code 0x%X\n", Status ); break; } break; } } case IOCTL_ALLOC_PHYSMEM: { SIZE_T NumberOfBytes = 0; PVOID va = 0; PHYSICAL_ADDRESS HighestAcceptableAddress = { 0xFFFFFFFF, 0xFFFFFFFF }; DbgPrint( "[chipsec] > IOCTL_ALLOC_PHYSMEM\n" ); pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UINT64) + sizeof(UINT32)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &HighestAcceptableAddress.QuadPart, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); RtlCopyBytes( &NumberOfBytes, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(UINT64), sizeof(UINT32) ); DbgPrint( "[chipsec] Allocating: NumberOfBytes = 0x%X, PhysAddr = 0x%I64x", NumberOfBytes, HighestAcceptableAddress.QuadPart ); va = MmAllocateContiguousMemory( NumberOfBytes, HighestAcceptableAddress ); if( !va ) { DbgPrint( "[chipsec] ERROR: STATUS_UNSUCCESSFUL - could not allocate memory\n" ); Status = STATUS_UNSUCCESSFUL; } else if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < 2*sizeof(UINT64) ) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL - should be at least 2*UINT64\n" ); Status = STATUS_BUFFER_TOO_SMALL; } else { PHYSICAL_ADDRESS pa = MmGetPhysicalAddress( va ); DbgPrint( "[chipsec] Allocated Buffer: VirtAddr = 0x%I64x, PhysAddr = 0x%I64x\n", (UINT64)va, pa.QuadPart ); ((UINT64*)pOutBuf)[0] = (UINT64)va; ((UINT64*)pOutBuf)[1] = pa.QuadPart; IrpSp->Parameters.Read.Length = 2*sizeof(UINT64); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; } break; } case IOCTL_FREE_PHYSMEM: { UINT64 va = 0x0; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_FREE_PHYSMEM\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &va, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); DbgPrint( "[chipsec][IOCTL_FREE_PHYSMEM] Virtual address of the memory being freed: 0x%I64X\n", va ); MmFreeContiguousMemory( (PVOID)va ); IrpSp->Parameters.Read.Length = 0; dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_GET_PHYSADDR: { UINT64 va = 0x0; PHYSICAL_ADDRESS pa = { 0x0, 0x0 }; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_GET_PHYSADDR\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( &va, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); pa = MmGetPhysicalAddress( (PVOID)va ); DbgPrint( "[chipsec][IOCTL_GET_PHYSADDR] Traslated virtual address 0x%I64X to physical: 0x%I64X\n", va, pa.QuadPart, pa.LowPart); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&pa, sizeof(UINT64) ); IrpSp->Parameters.Read.Length = sizeof(UINT64); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_MAP_IO_SPACE: { PVOID va = 0x0; PHYSICAL_ADDRESS pa = { 0x0, 0x0 }; unsigned int len = 0; unsigned int cache_type = 0; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_MAP_IO_SPACE\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != 3*8) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( &pa, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x00, 0x8 ); RtlCopyBytes( &len, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x08, 0x4 ); RtlCopyBytes( &cache_type, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x10, 0x4 ); va = MmMapIoSpace(pa, len, cache_type); DbgPrint( "[chipsec][IOCTL_MAP_IO_SPACE] Mapping physical address 0x%016llX to virtual 0x%016llX\n", pa, va); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&va, sizeof(va) ); IrpSp->Parameters.Read.Length = sizeof(va); dwBytesWritten = sizeof(va); Status = STATUS_SUCCESS; break; } case IOCTL_LOAD_UCODE_PATCH: { PVOID ucode_buf = NULL; UINT64 ucode_start = 0; UINT16 ucode_size = 0; UINT32 _eax = 0, _edx = 0; int CPUInfo[4] = {-1}; DbgPrint("[chipsec] > IOCTL_LOAD_UCODE_UPDATE\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + sizeof(UINT16) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < 3)\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( &ucode_size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(UINT16) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Ucode update size = 0x%X\n", ucode_size ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < ucode_size + sizeof(BYTE) + sizeof(UINT16) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < ucode_size + 3)\n" ); Status = STATUS_INVALID_PARAMETER; break; } ucode_buf = ExAllocatePoolWithTag( NonPagedPool, ucode_size, 0x3184 ); if( !ucode_buf ) { DbgPrint( "[chipsec] ERROR: couldn't allocate pool for ucode binary\n" ); break; } RtlCopyBytes( ucode_buf, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE) + sizeof(UINT16), ucode_size ); ucode_start = (UINT64)ucode_buf; DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] ucode update address = 0x%p (eax = 0x%08X, edx = 0x%08X)\n", ucode_start, (UINT32)(ucode_start & 0xFFFFFFFF), (UINT32)((ucode_start >> 32) & 0xFFFFFFFF) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] ucode update contents:\n" ); _dump_buffer( (unsigned char *)ucode_buf, min(ucode_size,0x100) ); // -- // -- trigger CPU ucode patch update // -- pInBuf points to the beginning of ucode update binary // -- _wrmsr( MSR_IA32_BIOS_UPDT_TRIG, (UINT32)((ucode_start >> 32) & 0xFFFFFFFF), (UINT32)(ucode_start & 0xFFFFFFFF) ); ExFreePoolWithTag( ucode_buf, 0x3184 ); // -- // -- check if patch was loaded // -- // -- need to clear IA32_BIOS_SIGN_ID MSR first // -- CPUID will deposit an update ID value in 64-bit MSR at address MSR_IA32_BIOS_SIGN_ID // -- read IA32_BIOS_SIGN_ID MSR to check patch ID != 0 // -- DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] checking ucode update was loaded..\n" ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] clear IA32_BIOS_SIGN_ID, CPUID EAX=1, read back IA32_BIOS_SIGN_ID\n" ); _wrmsr( MSR_IA32_BIOS_SIGN_ID, 0, 0 ); __cpuid(CPUInfo, 1); _rdmsr( MSR_IA32_BIOS_SIGN_ID, &_eax, &_edx ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] RDMSR( IA32_BIOS_SIGN_ID=0x8b ) = 0x%08x%08x\n", _edx, _eax ); if( 0 != _edx ) DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Microcode update loaded (ID != 0)\n" ); else DbgPrint( "[chipsec] ERROR: Microcode update failed\n" ); Status = STATUS_SUCCESS; break; } case IOCTL_WRMSR: { UINT32 msrData[3]; UINT32 _eax = 0, _edx = 0; unsigned int _msr_addr; DbgPrint("[chipsec] > IOCTL_WRMSR\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: STATUS_INVALID_PARAMETER (input buffer size < sizeof(BYTE) + 3*sizeof(UINT32))\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_WRMSR] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( msrData, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), 3 * sizeof(UINT32) ); _msr_addr = msrData[0]; _eax = msrData[1]; _edx = msrData[2]; DbgPrint( "[chipsec][IOCTL_WRMSR] WRMSR( 0x%x ) <-- 0x%08x%08x\n", _msr_addr, _edx, _eax ); // -- // -- write MSR // -- __try { _wrmsr( _msr_addr, _edx, _eax ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: exception code 0x%X\n", Status ); break; } // -- // -- read MSR to check if it was written // -- // _rdmsr( _msr_addr, &_eax, &_edx ); // DbgPrint( "[chipsec][IOCTL_WRMSR] RDMSR( 0x%x ) --> 0x%08x%08x\n", _msr_addr, _edx, _eax ); Status = STATUS_SUCCESS; break; } case IOCTL_RDMSR: { UINT32 msrData[1]; UINT32 _eax = 0; UINT32 _edx = 0; UINT32 _msr_addr = 0; DbgPrint("[chipsec] > IOCTL_RDMSR\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: No input provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + sizeof(UINT32) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER - input buffer size < sizeof(BYTE) + sizeof(UINT32)\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_RDMSR] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( msrData, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(UINT32) ); _msr_addr = msrData[0]; __try { _rdmsr( _msr_addr, &_eax, &_edx ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_RDMSR] ERROR: exception code 0x%X\n", Status ); break; } DbgPrint( "[chipsec][IOCTL_RDMSR] RDMSR( 0x%x ) --> 0x%08x%08x\n", _msr_addr, _edx, _eax ); if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= 2*sizeof(UINT32) ) { IrpSp->Parameters.Read.Length = 2*sizeof(UINT32); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&_eax, sizeof(UINT32) ); RtlCopyBytes( ((UINT8*)Irp->AssociatedIrp.SystemBuffer) + sizeof(UINT32), (VOID*)&_edx, sizeof(UINT32) ); dwBytesWritten = 2*sizeof(UINT32); Status = STATUS_SUCCESS; } else { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL - should be at least 2 UINT32\n" ); Status = STATUS_BUFFER_TOO_SMALL; } break; } case READ_IO_PORT: { DWORD value; BYTE size = 0; WORD io_port; DbgPrint( "[chipsec] > READ_IO_PORT\n" ); RtlCopyBytes( &io_port, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(WORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD), sizeof(BYTE) ); if( 1 != size && 2 != size && 4 != size) { DbgPrint( "[chipsec][READ_IO_PORT] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } __try { value = ReadIOPort( io_port, size ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][READ_IO_PORT] ERROR: exception code 0x%X\n", Status ); break; } IrpSp->Parameters.Read.Length = size; RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&value, size ); DbgPrint( "[chipsec][READ_IO_PORT] I/O Port %#04x, value = %#010x (size = %#02x)\n", io_port, value, size ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case WRITE_IO_PORT: { DWORD value = 0; WORD io_port = 0; BYTE size = 0; DbgPrint( "[chipsec] > WRITE_IO_PORT\n" ); RtlCopyBytes( &io_port, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(WORD) ); RtlCopyBytes( &value, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD), sizeof(DWORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD) + sizeof(DWORD), sizeof(BYTE) ); DbgPrint( "[chipsec][WRITE_IO_PORT] I/O Port %#04x, value = %#010x (size = %#02x)\n", io_port, value, size ); __try { WriteIOPort( value, io_port, size ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][WRITE_IO_PORT] ERROR: exception code 0x%X\n", Status ); break; } Status = STATUS_SUCCESS; break; } case GET_CPU_DESCRIPTOR_TABLE: { BYTE dt_code = 0; DESCRIPTOR_TABLE_RECORD dtr; PDESCRIPTOR_TABLE_RECORD pdtr = &dtr; PHYSICAL_ADDRESS dt_pa; DbgPrint( "[chipsec] > GET_CPU_DESCRIPTOR_TABLE\n" ); RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( &dt_code, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(BYTE) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table: %x\n", dt_code ); switch( dt_code ) { case CPU_DT_CODE_GDTR: { _store_gdtr( (void*)pdtr ); break; } case CPU_DT_CODE_LDTR: { _store_ldtr( (void*)pdtr ); break; } case CPU_DT_CODE_IDTR: default: { _store_idtr( (void*)pdtr ); break; } } DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table register contents:\n" ); _dump_buffer( (unsigned char *)pdtr, sizeof(DESCRIPTOR_TABLE_RECORD) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] IDTR: Limit = 0x%04x, Base = 0x%I64x\n", dtr.limit, dtr.base ); dt_pa = MmGetPhysicalAddress( (PVOID)dtr.base ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table PA: 0x%I64X (0x%08X_%08X)\n", dt_pa.QuadPart, dt_pa.HighPart, dt_pa.LowPart ); IrpSp->Parameters.Read.Length = sizeof(DESCRIPTOR_TABLE_RECORD) + sizeof(dt_pa.QuadPart); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)pdtr, sizeof(DESCRIPTOR_TABLE_RECORD) ); RtlCopyBytes( (UINT8*)Irp->AssociatedIrp.SystemBuffer + sizeof(DESCRIPTOR_TABLE_RECORD), (VOID*)&dt_pa.QuadPart, sizeof(dt_pa.QuadPart) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_SWSMI: { CPU_REG_TYPE gprs[6] = {0}; CPU_REG_TYPE _rax = 0, _rbx = 0, _rcx = 0, _rdx = 0, _rsi = 0, _rdi = 0; unsigned int _smi_code_data = 0; DbgPrint("[chipsec] > IOCTL_SWSMI\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UINT16) + sizeof(gprs) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < sizeof(UINT16) + sizeof(gprs))\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &_smi_code_data, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT16) ); RtlCopyBytes( gprs, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(UINT16), sizeof(gprs) ); _rax = gprs[ 0 ]; _rbx = gprs[ 1 ]; _rcx = gprs[ 2 ]; _rdx = gprs[ 3 ]; _rsi = gprs[ 4 ]; _rdi = gprs[ 5 ]; DbgPrint( "[chipsec][IOCTL_SWSMI] SW SMI to ports 0x%X-0x%X <- 0x%04X\n", 0xB2, 0xB3, _smi_code_data ); DbgPrint( " RAX = 0x%I64x\n", _rax ); DbgPrint( " RBX = 0x%I64x\n", _rbx ); DbgPrint( " RCX = 0x%I64x\n", _rcx ); DbgPrint( " RDX = 0x%I64x\n", _rdx ); DbgPrint( " RSI = 0x%I64x\n", _rsi ); DbgPrint( " RDI = 0x%I64x\n", _rdi ); // -- // -- send SMI using port 0xB2 // -- __try { _swsmi( _smi_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); break; } Status = STATUS_SUCCESS; break; } case IOCTL_CPUID: { DWORD CPUInfo[4] = {-1}; DWORD gprs[2] = {0}; DWORD _rax = 0, _rcx = 0; //CPU_REG_TYPE gprs[6]; //CPU_REG_TYPE _rax = 0, _rbx = 0, _rcx = 0, _rdx = 0, _rsi = 0, _rdi = 0; DbgPrint("[chipsec] > IOCTL_CPUID\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(gprs) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < %d)\n", sizeof(gprs) ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( gprs, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(gprs) ); _rax = gprs[ 0 ]; _rcx = gprs[ 1 ]; DbgPrint( "[chipsec][IOCTL_CPUID] CPUID:\n" ); DbgPrint( " EAX = 0x%08X\n", _rax ); DbgPrint( " ECX = 0x%08X\n", _rcx ); __cpuidex( CPUInfo, _rax, _rcx ); DbgPrint( "[chipsec][IOCTL_CPUID] CPUID returned:\n" ); DbgPrint( " EAX = 0x%08X\n", CPUInfo[0] ); DbgPrint( " EBX = 0x%08X\n", CPUInfo[1] ); DbgPrint( " ECX = 0x%08X\n", CPUInfo[2] ); DbgPrint( " EDX = 0x%08X\n", CPUInfo[3] ); IrpSp->Parameters.Read.Length = sizeof(CPUInfo); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)CPUInfo, sizeof(CPUInfo) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_WRCR: { UINT64 val64 = 0; CPU_REG_TYPE value = 0; WORD cr_reg = 0; DbgPrint( "[chipsec] > WRITE_CR\n" ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (sizeof(cr_reg) + sizeof(val64) + sizeof(BYTE))) { Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &cr_reg, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(cr_reg) ); RtlCopyBytes( &val64, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg), sizeof(val64) ); new_cpu_thread_id = *((BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg) + sizeof(val64)); if( new_cpu_thread_id >= _num_active_cpus ) { // new_cpu_thread_id = 0; Status = STATUS_INVALID_PARAMETER; break; } KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); value = (CPU_REG_TYPE)val64; DbgPrint( "[chipsec][WRITE_CR] CR Reg %#04x, value = %#010x \n", cr_reg, value ); switch (cr_reg) { case 0: WriteCR0(value); Status = STATUS_SUCCESS; break; case 2: WriteCR2(value); Status = STATUS_SUCCESS; break; case 3: WriteCR3(value); Status = STATUS_SUCCESS; break; case 4: WriteCR4(value); Status = STATUS_SUCCESS; break; case 8: #if defined(_M_AMD64) WriteCR8(value); Status = STATUS_SUCCESS; break; #endif default: Status = STATUS_INVALID_PARAMETER; break; } if( !NT_SUCCESS(Status) ) { break; } dwBytesWritten = 0; Status = STATUS_SUCCESS; break; } case IOCTL_RDCR: { UINT64 val64 = 0; CPU_REG_TYPE value = 0; WORD cr_reg = 0; DbgPrint( "[chipsec] > READ_CR\n" ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (sizeof(cr_reg)+sizeof(BYTE)) || IrpSp->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(val64)) ) { Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &cr_reg, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(cr_reg) ); new_cpu_thread_id = *((BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg)); if( new_cpu_thread_id >= _num_active_cpus ) { // new_cpu_thread_id = 0; Status = STATUS_INVALID_PARAMETER; break; } KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); switch (cr_reg) { case 0: value = ReadCR0(); Status = STATUS_SUCCESS; break; case 2: value = ReadCR2(); Status = STATUS_SUCCESS; break; case 3: value = ReadCR3(); Status = STATUS_SUCCESS; break; case 4: value = ReadCR4(); Status = STATUS_SUCCESS; break; case 8: #if defined(_M_AMD64) value = ReadCR8(); Status = STATUS_SUCCESS; break; #endif default: Status = STATUS_INVALID_PARAMETER; break; } if( !NT_SUCCESS(Status) ) { break; } val64 = value; RtlCopyBytes( (BYTE*)Irp->AssociatedIrp.SystemBuffer, &val64, sizeof(val64) ); dwBytesWritten = sizeof(val64); DbgPrint( "[chipsec][READ_CR] CR Reg %#04x, value = %#010x \n", cr_reg, value ); Status = STATUS_SUCCESS; break; } case IOCTL_HYPERCALL: { CPU_REG_TYPE regs[11] = {0}; CPU_REG_TYPE result = 0; DbgPrint("[chipsec] > IOCTL_HYPERCALL\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(regs)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(result)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( regs, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(regs) ); DbgPrint( "[chipsec][IOCTL_HYPERCALL] HYPERCALL:\n" ); #if defined(_M_AMD64) DbgPrint( " RCX = 0x%016llX RDX = 0x%016llX\n", regs[0], regs[1] ); DbgPrint( " R8 = 0x%016llX R9 = 0x%016llX\n", regs[2], regs[3] ); DbgPrint( " R10 = 0x%016llX R11 = 0x%016llX\n", regs[4], regs[5] ); DbgPrint( " RAX = 0x%016llX RBX = 0x%016llX\n", regs[6], regs[7] ); DbgPrint( " RDI = 0x%016llX RSI = 0x%016llX\n", regs[8], regs[9] ); #endif #if defined(_M_IX86) DbgPrint( " EAX = 0x%08X EBX = 0x%08X ECX = 0x%08X\n", regs[6], regs[7], regs[0] ); DbgPrint( " EDX = 0x%08X ESI = 0x%08X EDI = 0x%08X\n", regs[1], regs[8], regs[9] ); #endif DbgPrint( " XMM0-XMM5 buffer VA = 0x%016llX\n", regs[9] ); __try { result = hypercall(regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7], regs[8], regs[9], regs[10], &hypercall_page); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_HYPERCALL] ERROR: exception code 0x%X\n", Status ); break; } DbgPrint( "[chipsec][IOCTL_HYPERCALL] returned: 0x%016llX\n", result); IrpSp->Parameters.Read.Length = sizeof(result); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&result, sizeof(result) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } default: DbgPrint( "[chipsec] ERROR: invalid IOCTL\n"); Status = STATUS_NOT_IMPLEMENTED; break; } // -- switch
dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } default: DbgPrint( "[chipsec] ERROR: invalid IOCTL\n"); Status = STATUS_NOT_IMPLEMENTED; break; } // -- switch // -- restore current KAFFINITY KeSetSystemAffinityThread( _kaffinity ); DbgPrint( "[chipsec] Restored active CPU mask (KAFFINITY): 0x%08X\n", KeQueryActiveProcessors() ); DbgPrint( "[chipsec] Current CPU thread : %d\n", KeGetCurrentProcessorNumber() ); // -- // -- Complete the I/O request, Record the status of the I/O action. // -- Irp->IoStatus.Status = Status; Irp->IoStatus.Information = dwBytesWritten; DbgPrint( "[chipsec] Irp->IoStatus.Status = 0x%x, Irp->IoStatus.Information = 0x%x\n", Irp->IoStatus.Status, Irp->IoStatus.Information ); DbgPrint( "[chipsec]\n" ); IoCompleteRequest( Irp, IO_NO_INCREMENT ); return Status; }
/** * Internal worker for the RTMpOn* APIs. * * @returns IPRT status code. * @param pfnWorker The callback. * @param pvUser1 User argument 1. * @param pvUser2 User argument 2. * @param enmCpuid What to do / is idCpu valid. * @param idCpu Used if enmCpuid is RT_NT_CPUID_SPECIFIC or * RT_NT_CPUID_PAIR, otherwise ignored. * @param idCpu2 Used if enmCpuid is RT_NT_CPUID_PAIR, otherwise ignored. * @param pcHits Where to return the number of this. Optional. */ static int rtMpCallUsingDpcs(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2, RT_NT_CPUID enmCpuid, RTCPUID idCpu, RTCPUID idCpu2, uint32_t *pcHits) { PRTMPARGS pArgs; KDPC *paExecCpuDpcs; #if 0 /* KeFlushQueuedDpcs must be run at IRQL PASSIVE_LEVEL according to MSDN, but the * driver verifier doesn't complain... */ AssertMsg(KeGetCurrentIrql() == PASSIVE_LEVEL, ("%d != %d (PASSIVE_LEVEL)\n", KeGetCurrentIrql(), PASSIVE_LEVEL)); #endif #ifdef IPRT_TARGET_NT4 KAFFINITY Mask; /* g_pfnrtNt* are not present on NT anyway. */ return VERR_NOT_SUPPORTED; #else KAFFINITY Mask = KeQueryActiveProcessors(); #endif /* KeFlushQueuedDpcs is not present in Windows 2000; import it dynamically so we can just fail this call. */ if (!g_pfnrtNtKeFlushQueuedDpcs) return VERR_NOT_SUPPORTED; pArgs = (PRTMPARGS)ExAllocatePoolWithTag(NonPagedPool, MAXIMUM_PROCESSORS*sizeof(KDPC) + sizeof(RTMPARGS), (ULONG)'RTMp'); if (!pArgs) return VERR_NO_MEMORY; pArgs->pfnWorker = pfnWorker; pArgs->pvUser1 = pvUser1; pArgs->pvUser2 = pvUser2; pArgs->idCpu = NIL_RTCPUID; pArgs->idCpu2 = NIL_RTCPUID; pArgs->cHits = 0; pArgs->cRefs = 1; paExecCpuDpcs = (KDPC *)(pArgs + 1); if (enmCpuid == RT_NT_CPUID_SPECIFIC) { KeInitializeDpc(&paExecCpuDpcs[0], rtmpNtDPCWrapper, pArgs); KeSetImportanceDpc(&paExecCpuDpcs[0], HighImportance); KeSetTargetProcessorDpc(&paExecCpuDpcs[0], (int)idCpu); pArgs->idCpu = idCpu; } else if (enmCpuid == RT_NT_CPUID_SPECIFIC) { KeInitializeDpc(&paExecCpuDpcs[0], rtmpNtDPCWrapper, pArgs); KeSetImportanceDpc(&paExecCpuDpcs[0], HighImportance); KeSetTargetProcessorDpc(&paExecCpuDpcs[0], (int)idCpu); pArgs->idCpu = idCpu; KeInitializeDpc(&paExecCpuDpcs[1], rtmpNtDPCWrapper, pArgs); KeSetImportanceDpc(&paExecCpuDpcs[1], HighImportance); KeSetTargetProcessorDpc(&paExecCpuDpcs[1], (int)idCpu2); pArgs->idCpu2 = idCpu2; } else { for (unsigned i = 0; i < MAXIMUM_PROCESSORS; i++) { KeInitializeDpc(&paExecCpuDpcs[i], rtmpNtDPCWrapper, pArgs); KeSetImportanceDpc(&paExecCpuDpcs[i], HighImportance); KeSetTargetProcessorDpc(&paExecCpuDpcs[i], i); } } /* Raise the IRQL to DISPATCH_LEVEL so we can't be rescheduled to another cpu. * KeInsertQueueDpc must also be executed at IRQL >= DISPATCH_LEVEL. */ KIRQL oldIrql; KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); /* * We cannot do other than assume a 1:1 relationship between the * affinity mask and the process despite the warnings in the docs. * If someone knows a better way to get this done, please let bird know. */ ASMCompilerBarrier(); /* paranoia */ if (enmCpuid == RT_NT_CPUID_SPECIFIC) { ASMAtomicIncS32(&pArgs->cRefs); BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[0], 0, 0); Assert(ret); } else if (enmCpuid == RT_NT_CPUID_PAIR) { ASMAtomicIncS32(&pArgs->cRefs); BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[0], 0, 0); Assert(ret); ASMAtomicIncS32(&pArgs->cRefs); ret = KeInsertQueueDpc(&paExecCpuDpcs[1], 0, 0); Assert(ret); } else { unsigned iSelf = KeGetCurrentProcessorNumber(); for (unsigned i = 0; i < MAXIMUM_PROCESSORS; i++) { if ( (i != iSelf) && (Mask & RT_BIT_64(i))) { ASMAtomicIncS32(&pArgs->cRefs); BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[i], 0, 0); Assert(ret); } } if (enmCpuid != RT_NT_CPUID_OTHERS) pfnWorker(iSelf, pvUser1, pvUser2); } KeLowerIrql(oldIrql); /* Flush all DPCs and wait for completion. (can take long!) */ /** @todo Consider changing this to an active wait using some atomic inc/dec * stuff (and check for the current cpu above in the specific case). */ /** @todo Seems KeFlushQueuedDpcs doesn't wait for the DPCs to be completely * executed. Seen pArgs being freed while some CPU was using it before * cRefs was added. */ g_pfnrtNtKeFlushQueuedDpcs(); if (pcHits) *pcHits = pArgs->cHits; /* Dereference the argument structure. */ int32_t cRefs = ASMAtomicDecS32(&pArgs->cRefs); Assert(cRefs >= 0); if (cRefs == 0) ExFreePool(pArgs); return VINF_SUCCESS; }
// // Packet Driver's entry routine. // NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NDIS_PROTOCOL_CHARACTERISTICS ProtocolChar; PDEVICE_OBJECT DeviceObject = NULL; PDEVICE_EXTENSION DeviceExtension = NULL; NTSTATUS Status = STATUS_SUCCESS; NTSTATUS ErrorCode = STATUS_SUCCESS; NDIS_STRING ProtoName = NDIS_STRING_CONST("PacketDriver"); ULONG DevicesCreated=0; NDIS_HANDLE NdisProtocolHandle; WCHAR* bindT; PKEY_VALUE_PARTIAL_INFORMATION tcpBindingsP; UNICODE_STRING macName; ULONG OsMajorVersion, OsMinorVersion; PsGetVersion(&OsMajorVersion, &OsMinorVersion, NULL, NULL); // // Define the correct flag to skip the loopback packets, according to the OS // if((OsMajorVersion == 5) && (OsMinorVersion == 0)) { // Windows 2000 wants both NDIS_FLAGS_DONT_LOOPBACK and NDIS_FLAGS_SKIP_LOOPBACK g_SendPacketFlags = NDIS_FLAGS_DONT_LOOPBACK | NDIS_FLAGS_SKIP_LOOPBACK_W2K; } else { // Windows XP, 2003 and following want only NDIS_FLAGS_DONT_LOOPBACK g_SendPacketFlags = NDIS_FLAGS_DONT_LOOPBACK; } if (((OsMajorVersion == 6) && (OsMinorVersion >= 1)) || (OsMajorVersion >= 7)) { // Use KeQueryActiveProcessors to get the number of CPUs in Windows 7 or later KAFFINITY cpus = KeQueryActiveProcessors(); NCpu = 0; while (cpus) { if (cpus % 2) { NCpu++; } cpus = cpus / 2; } } else { // Use NdisSystemProcessorCount in Windows Vista or earlier NCpu = NdisSystemProcessorCount(); } ReadTimeStampModeFromRegistry(RegistryPath); IF_LOUD(DbgPrint("%ws",RegistryPath->Buffer);)
NTSTATUS OnDriverDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION IrpSp; ULONG ControlCode = 0; ULONG dwBytesWritten = 0; PCHAR pInBuf = NULL, pOutBuf = NULL; KAFFINITY affinity = 0; UNREFERENCED_PARAMETER(DeviceObject); IrpSp = IoGetCurrentIrpStackLocation(Irp); ControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; affinity = KeQueryActiveProcessors(); Irp->IoStatus.Information = 0; switch (ControlCode) { case IOCTL_GET_SYSTEM_MODULES: { ULONG bytes = 0; PRTL_PROCESS_MODULES pMods = NULL; DbgPrint ("[R2K] IOCTL_GET_SYSTEM_MODULES\n"); if (!Irp->AssociatedIrp.SystemBuffer) { DbgPrint ("[R2K] IOCTL_GET_SYSTEM_MODULES ERROR: STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; break; } pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; Status = ZwQuerySystemInformation (SystemModuleInformation, 0, bytes, &bytes); if (bytes == 0) { DbgPrint ("[R2K] IOCTL_GET_SYSTEM_MODULES ERROR: Invalid SystemModuleInformation size\n"); Status = STATUS_UNSUCCESSFUL; break; } if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < bytes) { DbgPrint ("[R2K] IOCTL_GET_SYSTEM_MODULES ERROR: STATUS_BUFFER_TOO_SMALL\n"); Status = STATUS_BUFFER_TOO_SMALL; break; } pMods = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag (NonPagedPool, bytes, 'domP'); RtlZeroMemory(pMods, bytes); Status = ZwQuerySystemInformation (SystemModuleInformation, pMods, bytes, &bytes); RtlCopyMemory (pOutBuf, (void*)pMods, bytes); if (pMods) ExFreePoolWithTag (pMods, 'domP'); dwBytesWritten = bytes; Status = STATUS_SUCCESS; break; } case IOCTL_READ_KERNEL_MEM: { UINT32 len = 0; LARGE_INTEGER virt_addr = { 0x0, 0x0 }; if (!Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3 * sizeof(UINT32)) { DbgPrint ("[R2K] IOCTL_READ_KERNEL_MEM ERROR: STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; break; } pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; virt_addr.LowPart = ((UINT32*)pInBuf)[0]; virt_addr.HighPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; if (!len) len = 4; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < len) { DbgPrint ("[R2K] IOCTL_READ_KERNEL_MEM ERROR: STATUS_BUFFER_TOO_SMALL\n"); Status = STATUS_BUFFER_TOO_SMALL; break; } __try { // is addres + len valid page? if (!MmIsAddressValid ((void*)(LONG_PTR)(virt_addr.QuadPart + len))) { DbgPrint ("[R2K] IOCTL_READ_KERNEL_MEM: Error page not valid at addres + len %p\n", (virt_addr.QuadPart + len)); Status = STATUS_ACCESS_DENIED; break; } if (MmIsAddressValid ((void*)(LONG_PTR)virt_addr.QuadPart)) { DbgPrint ("[R2K] IOCTL_READ_KERNEL_MEM: Reading address: %p\n", virt_addr.QuadPart); DbgPrint (" Bytes to read : %u\n", len); RtlCopyMemory (pOutBuf, (void*)(LONG_PTR)virt_addr.QuadPart, len); Status = STATUS_SUCCESS; } else { DbgPrint ("[R2K] IOCTL_READ_KERNEL_MEM: Error page not valid %p\n", virt_addr.QuadPart); Status = STATUS_ACCESS_DENIED; break; } } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode (); DbgPrint ("[R2K] IOCTL_READ_KERNEL_MEM ERROR: exception code 0x%X\n", Status); break; } if (NT_SUCCESS (Status)) { dwBytesWritten = len; } break; } case IOCTL_WRITE_KERNEL_MEM: { UINT32 len = 0; LARGE_INTEGER virt_addr = { 0x0, 0x0 }; unsigned char* buffer = 0; if (!Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < 4 * sizeof(UINT32)) { DbgPrint ("[R2K] IOCTL_WRITE_KERNEL_MEM ERROR: STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; break; } pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; virt_addr.LowPart = ((UINT32*)pInBuf)[0]; virt_addr.HighPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; buffer = (unsigned char *)&((UINT32*)pInBuf)[3]; if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength - (4 * sizeof(UINT32))) < len) { DbgPrint ("[R2K] IOCTL_WRITE_KERNEL_MEM ERROR: buffer smaller than specified\n"); Status = STATUS_INVALID_PARAMETER; break; } __try { // is addres + len valid page? if (!MmIsAddressValid ((void*)(LONG_PTR)(virt_addr.QuadPart + len))) { DbgPrint ("[R2K] IOCTL_WRITE_KERNEL_MEM: Error page not valid at addres + len %p\n", (virt_addr.QuadPart + len)); Status = STATUS_ACCESS_DENIED; break; } if (MmIsAddressValid ((void*)(LONG_PTR)virt_addr.QuadPart)) { DbgPrint ("[R2K] IOCTL_WRITE_KERNEL_MEM: Writing address: %p\n", virt_addr.QuadPart); DbgPrint (" Bytes to Write : %u\n", len); RtlCopyMemory ((void*)(LONG_PTR)virt_addr.QuadPart, (void*)buffer, len); Status = STATUS_SUCCESS; } else { DbgPrint ("[R2K] IOCTL_WRITE_KERNEL_MEM: Error page not valid %p\n", virt_addr.QuadPart); Status = STATUS_ACCESS_DENIED; break; } } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode (); DbgPrint ("[R2K] IOCTL_READ_KERNEL_MEM ERROR: exception code 0x%X\n", Status); break; } if (NT_SUCCESS(Status)) { dwBytesWritten = len; } break; } case IOCTL_READ_PHYS_MEM: { UINT32 len = 0; PHYSICAL_ADDRESS phys_addr = { 0x0, 0x0 }; DbgPrint ("[R2K] IOCTL_READ_PHYS_MEM\n"); if (!Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3 * sizeof(UINT32)) { DbgPrint ("[R2K] IOCTL_READ_PHYS_MEM ERROR: STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; break; } pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; phys_addr.LowPart = ((UINT32*)pInBuf)[0]; phys_addr.HighPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; if (!len) len = 4; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < len) { DbgPrint ("[R2K] IOCTL_READ_PHYS_MEM ERROR: STATUS_BUFFER_TOO_SMALL\n"); Status = STATUS_BUFFER_TOO_SMALL; break; } __try { void * va = MmMapIoSpace (phys_addr, len, MmCached); if (!va) { DbgPrint ("[R2K] IOCTL_READ_PHYS_MEM ERROR: no space for mapping\n"); return STATUS_UNSUCCESSFUL; } DbgPrint ("[R2K] IOCTL_READ_PHYS_MEM reading %d bytes from physical address 0x%08x_%08x (virtual = %p)", len, phys_addr.HighPart, phys_addr.LowPart, va); RtlCopyMemory (pOutBuf, va, len); MmUnmapIoSpace (va, len); Status = STATUS_SUCCESS; } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode (); DbgPrint ("[R2K] IOCTL_READ_PHYS_MEM ERROR: exception code 0x%X\n", Status); break; } if (NT_SUCCESS(Status)) { DbgPrint ("[R2K] IOCTL_READ_PHYS_MEM Contents:\n"); //DumpBuffer((unsigned char *)pOutBuf, min(len, 0x100)); dwBytesWritten = len; } break; } case IOCTL_WRITE_PHYS_MEM: { UINT32 len = 0; PHYSICAL_ADDRESS phys_addr = { 0x0, 0x0 }; DbgPrint ("[R2K] IOCTL_WRITE_PHYS_MEM\n"); if (Irp->AssociatedIrp.SystemBuffer) { pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3 * sizeof(UINT32)) { DbgPrint ("[R2K] IOCTL_WRITE_PHYS_MEM ERROR: STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; break; } phys_addr.LowPart = ((UINT32*)pInBuf)[0]; phys_addr.HighPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; pInBuf = (PCHAR)(((UINT32*)pInBuf) + 3); if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < len + 3 * sizeof(UINT32)) { DbgPrint ("[R2K] IOCTL_WRITE_PHYS_MEM ERROR: STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; break; } __try { void * va = MmMapIoSpace (phys_addr, len, MmCached); if (!va) { DbgPrint ("[R2K] IOCTL_WRITE_PHYS_MEM ERROR: no space for mapping\n"); return STATUS_UNSUCCESSFUL; } //DbgPrint("[R2K] IOCTL_WRITE_PHYS_MEM writing %d bytes to physical address 0x%08x_%08x (virtual = %#010x)", len, phys_addr.HighPart, phys_addr.LowPart, (unsigned int)va); RtlCopyMemory (va, pInBuf, len); MmUnmapIoSpace (va, len); Status = STATUS_SUCCESS; } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode (); DbgPrint ("[R2K] IOCTL_WRITE_PHYS_MEM ERROR: exception code 0x%X\n", Status); } } break; } case IOCTL_GET_PHYSADDR: { UINT64 va = 0x0; PHYSICAL_ADDRESS pa = { 0x0, 0x0 }; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint ("[R2K] IOCTL_GET_PHYSADDR\n"); if (!Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UINT64)) { DbgPrint ("[R2K] IOCTL_GET_PHYSADDR ERROR: STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; break; } if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT64)) { DbgPrint ("[R2K] IOCTL_GET_PHYSADDR ERROR: STATUS_BUFFER_TOO_SMALL\n"); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes (&va, (unsigned char*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64)); pa = MmGetPhysicalAddress ((PVOID)(ULONG_PTR)va); DbgPrint ("[R2K] IOCTL_GET_PHYSADDR Traslated virtual address 0x%I64X to physical: 0x%I64X\n", va, pa.QuadPart, pa.LowPart); RtlCopyBytes (Irp->AssociatedIrp.SystemBuffer, (void*)&pa, sizeof(UINT64)); IrpSp->Parameters.Read.Length = sizeof(UINT64); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } default: Status = STATUS_NOT_SUPPORTED; break; }
DECLHIDDEN(int) rtR0InitNative(void) { /* * Init the Nt cpu set. */ #ifdef IPRT_TARGET_NT4 KAFFINITY ActiveProcessors = (UINT64_C(1) << KeNumberProcessors) - UINT64_C(1); #else KAFFINITY ActiveProcessors = KeQueryActiveProcessors(); #endif RTCpuSetEmpty(&g_rtMpNtCpuSet); RTCpuSetFromU64(&g_rtMpNtCpuSet, ActiveProcessors); /** @todo Port to W2K8 with > 64 cpus/threads. */ /* * Initialize the function pointers. */ #ifdef IPRT_TARGET_NT4 g_pfnrtNtExSetTimerResolution = NULL; g_pfnrtNtKeFlushQueuedDpcs = NULL; g_pfnrtHalRequestIpiW7Plus = NULL; g_pfnrtHalRequestIpiPreW7 = NULL; g_pfnrtNtHalSendSoftwareInterrupt = NULL; g_pfnrtKeIpiGenericCall = NULL; g_pfnrtKeInitializeAffinityEx = NULL; g_pfnrtKeAddProcessorAffinityEx = NULL; g_pfnrtKeGetProcessorIndexFromNumber = NULL; g_pfnrtRtlGetVersion = NULL; g_pfnrtKeQueryInterruptTime = NULL; g_pfnrtKeQueryInterruptTimePrecise = NULL; g_pfnrtKeQuerySystemTime = NULL; g_pfnrtKeQuerySystemTimePrecise = NULL; #else UNICODE_STRING RoutineName; RtlInitUnicodeString(&RoutineName, L"ExSetTimerResolution"); g_pfnrtNtExSetTimerResolution = (PFNMYEXSETTIMERRESOLUTION)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeFlushQueuedDpcs"); g_pfnrtNtKeFlushQueuedDpcs = (PFNMYKEFLUSHQUEUEDDPCS)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"HalRequestIpi"); g_pfnrtHalRequestIpiW7Plus = (PFNHALREQUESTIPI_W7PLUS)MmGetSystemRoutineAddress(&RoutineName); g_pfnrtHalRequestIpiPreW7 = (PFNHALREQUESTIPI_PRE_W7)g_pfnrtHalRequestIpiW7Plus; RtlInitUnicodeString(&RoutineName, L"HalSendSoftwareInterrupt"); g_pfnrtNtHalSendSoftwareInterrupt = (PFNHALSENDSOFTWAREINTERRUPT)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeIpiGenericCall"); g_pfnrtKeIpiGenericCall = (PFNRTKEIPIGENERICCALL)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeInitializeAffinityEx"); g_pfnrtKeInitializeAffinityEx = (PFNKEINITIALIZEAFFINITYEX)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeAddProcessorAffinityEx"); g_pfnrtKeAddProcessorAffinityEx = (PFNKEADDPROCESSORAFFINITYEX)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeGetProcessorIndexFromNumber"); g_pfnrtKeGetProcessorIndexFromNumber = (PFNKEGETPROCESSORINDEXFROMNUMBER)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"RtlGetVersion"); g_pfnrtRtlGetVersion = (PFNRTRTLGETVERSION)MmGetSystemRoutineAddress(&RoutineName); # ifndef RT_ARCH_AMD64 RtlInitUnicodeString(&RoutineName, L"KeQueryInterruptTime"); g_pfnrtKeQueryInterruptTime = (PFNRTKEQUERYINTERRUPTTIME)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeQuerySystemTime"); g_pfnrtKeQuerySystemTime = (PFNRTKEQUERYSYSTEMTIME)MmGetSystemRoutineAddress(&RoutineName); # endif RtlInitUnicodeString(&RoutineName, L"KeQueryInterruptTimePrecise"); g_pfnrtKeQueryInterruptTimePrecise = (PFNRTKEQUERYINTERRUPTTIMEPRECISE)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeQuerySystemTimePrecise"); g_pfnrtKeQuerySystemTimePrecise = (PFNRTKEQUERYSYSTEMTIMEPRECISE)MmGetSystemRoutineAddress(&RoutineName); #endif /* * HACK ALERT! (and déjà vu warning - remember win32k.sys?) * * Try find _KPRCB::QuantumEnd and _KPRCB::[DpcData.]DpcQueueDepth. * For purpose of verification we use the VendorString member (12+1 chars). * * The offsets was initially derived by poking around with windbg * (dt _KPRCB, !prcb ++, and such like). Systematic harvesting was then * planned using dia2dump, grep and the symbol pack in a manner like this: * dia2dump -type _KDPC_DATA -type _KPRCB EXE\ntkrnlmp.pdb | grep -wE "QuantumEnd|DpcData|DpcQueueDepth|VendorString" * * The final solution ended up using a custom harvester program called * ntBldSymDb that recursively searches thru unpacked symbol packages for * the desired structure offsets. The program assumes that the packages * are unpacked into directories with the same name as the package, with * exception of some of the w2k packages which requires a 'w2k' prefix to * be distinguishable from another. */ RTNTSDBOSVER OsVerInfo; rtR0NtGetOsVersionInfo(&OsVerInfo); /* * Gather consistent CPU vendor string and PRCB pointers. */ KIRQL OldIrql; KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); /* make sure we stay on the same cpu */ union { uint32_t auRegs[4]; char szVendor[4*3+1]; } u; ASMCpuId(0, &u.auRegs[3], &u.auRegs[0], &u.auRegs[2], &u.auRegs[1]); u.szVendor[4*3] = '\0'; uint8_t *pbPrcb; __try /* Warning. This try/except statement may provide some false safety. */ { #if defined(RT_ARCH_X86) PKPCR pPcr = (PKPCR)__readfsdword(RT_OFFSETOF(KPCR,SelfPcr)); pbPrcb = (uint8_t *)pPcr->Prcb; #elif defined(RT_ARCH_AMD64) PKPCR pPcr = (PKPCR)__readgsqword(RT_OFFSETOF(KPCR,Self)); pbPrcb = (uint8_t *)pPcr->CurrentPrcb; #else # error "port me" pbPrcb = NULL; #endif } __except(EXCEPTION_EXECUTE_HANDLER) { pbPrcb = NULL; } /* * Search the database */ if (pbPrcb) { /* Find the best matching kernel version based on build number. */ uint32_t iBest = UINT32_MAX; int32_t iBestDelta = INT32_MAX; for (uint32_t i = 0; i < RT_ELEMENTS(g_artNtSdbSets); i++) { if (g_artNtSdbSets[i].OsVerInfo.fChecked != OsVerInfo.fChecked) continue; if (OsVerInfo.fSmp /*must-be-smp*/ && !g_artNtSdbSets[i].OsVerInfo.fSmp) continue; int32_t iDelta = RT_ABS((int32_t)OsVerInfo.uBuildNo - (int32_t)g_artNtSdbSets[i].OsVerInfo.uBuildNo); if ( iDelta == 0 && (g_artNtSdbSets[i].OsVerInfo.uCsdNo == OsVerInfo.uCsdNo || OsVerInfo.uCsdNo == MY_NIL_CSD)) { /* prefect */ iBestDelta = iDelta; iBest = i; break; } if ( iDelta < iBestDelta || iBest == UINT32_MAX || ( iDelta == iBestDelta && OsVerInfo.uCsdNo != MY_NIL_CSD && RT_ABS(g_artNtSdbSets[i ].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo) < RT_ABS(g_artNtSdbSets[iBest].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo) ) ) { iBestDelta = iDelta; iBest = i; } } if (iBest < RT_ELEMENTS(g_artNtSdbSets)) { /* Try all sets: iBest -> End; iBest -> Start. */ bool fDone = false; int32_t i = iBest; while ( i < RT_ELEMENTS(g_artNtSdbSets) && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo))) i++; if (!fDone) { i = (int32_t)iBest - 1; while ( i >= 0 && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo))) i--; } } else DbgPrint("IPRT: Failed to locate data set.\n"); } else DbgPrint("IPRT: Failed to get PCBR pointer.\n"); KeLowerIrql(OldIrql); /* Lowering the IRQL early in the hope that we may catch exceptions below. */ #ifndef IN_GUEST if (!g_offrtNtPbQuantumEnd && !g_offrtNtPbDpcQueueDepth) DbgPrint("IPRT: Neither _KPRCB::QuantumEnd nor _KPRCB::DpcQueueDepth was not found! Kernel %u.%u %u %s\n", OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free"); # ifdef DEBUG else DbgPrint("IPRT: _KPRCB:{.QuantumEnd=%x/%d, .DpcQueueDepth=%x/%d} Kernel %u.%u %u %s\n", g_offrtNtPbQuantumEnd, g_cbrtNtPbQuantumEnd, g_offrtNtPbDpcQueueDepth, OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free"); # endif #endif /* * Special IPI fun for RTMpPokeCpu. * * On Vista and later the DPC method doesn't seem to reliably send IPIs, * so we have to use alternative methods. The NtHalSendSoftwareInterrupt * is preferrable, but it's AMD64 only. The NalRequestIpip method changed * in Windows 7 with the lots-of-processors-support, but it's the only * targeted IPI game in town if we cannot use KeInsertQueueDpc. Worst case * we use broadcast IPIs. */ if ( OsVerInfo.uMajorVer > 6 || (OsVerInfo.uMajorVer == 6 && OsVerInfo.uMinorVer > 0)) g_pfnrtHalRequestIpiPreW7 = NULL; else g_pfnrtHalRequestIpiW7Plus = NULL; g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingDpc; #ifndef IPRT_TARGET_NT4 if (g_pfnrtNtHalSendSoftwareInterrupt) g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingHalSendSoftwareInterrupt; else if ( g_pfnrtHalRequestIpiW7Plus && g_pfnrtKeInitializeAffinityEx && g_pfnrtKeAddProcessorAffinityEx && g_pfnrtKeGetProcessorIndexFromNumber) g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingHalReqestIpiW7Plus; else if (OsVerInfo.uMajorVer >= 6 && g_pfnrtKeIpiGenericCall) g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingBroadcastIpi; /* else: Windows XP should send always send an IPI -> VERIFY */ #endif return VINF_SUCCESS; }
//-------------------------------------------------------------------------------------- NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { NTSTATUS ns = STATUS_INVALID_DEVICE_REQUEST; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); ULONG InSize = 0, OutSize = 0; Irp->IoStatus.Status = ns; Irp->IoStatus.Information = 0; if (stack->MajorFunction == IRP_MJ_DEVICE_CONTROL) { // get IOCTL parameters ULONG Code = stack->Parameters.DeviceIoControl.IoControlCode; PREQUEST_BUFFER Buff = (PREQUEST_BUFFER)Irp->AssociatedIrp.SystemBuffer; InSize = stack->Parameters.DeviceIoControl.InputBufferLength; OutSize = stack->Parameters.DeviceIoControl.OutputBufferLength; DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_DEVICE_CONTROL 0x%.8x\n", Code); // check buffer length if (InSize >= sizeof(REQUEST_BUFFER) && OutSize >= sizeof(REQUEST_BUFFER)) { switch (Code) { case IOCTL_DRV_CONTROL: { switch (Buff->Code) { case DRV_CTL_NONE: { // do nothing, just return successful status ns = STATUS_SUCCESS; break; } case DRV_CTL_VIRT_MEM_READ: { if (InSize >= sizeof(REQUEST_BUFFER) + Buff->MemRead.Size) { // read virtual memory memcpy( Buff->MemRead.Data, (PVOID)Buff->MemRead.Address, Buff->MemRead.Size ); ns = STATUS_SUCCESS; } break; } case DRV_CTL_VIRT_MEM_WRITE: { if (InSize >= sizeof(REQUEST_BUFFER) + Buff->MemWrite.Size) { // write virtual memory memcpy( (PVOID)Buff->MemWrite.Address, Buff->MemWrite.Data, Buff->MemWrite.Size ); ns = STATUS_SUCCESS; } break; } case DRV_CTL_PHYS_MEM_READ: { if (InSize >= sizeof(REQUEST_BUFFER) + Buff->MemRead.Size) { // read physical memory ns = HwPhysMemRead( Buff->MemRead.Address, Buff->MemRead.Size, Buff->MemRead.Data ); } break; } case DRV_CTL_PHYS_MEM_WRITE: { if (InSize >= sizeof(REQUEST_BUFFER) + Buff->MemWrite.Size) { // write physical memory ns = HwPhysMemWrite( Buff->MemWrite.Address, Buff->MemWrite.Size, Buff->MemWrite.Data ); } break; } case DRV_CTL_PHYS_MEM_MAP: { PPHYS_MEM_REGION MemRegion = Buff->MemMap.Regions; Buff->MemMap.RegionsCount = 0; if (f_MmGetPhysicalMemoryRanges) { // get physical memory information PPHYSICAL_MEMORY_RANGE MemInfo = f_MmGetPhysicalMemoryRanges(); if (MemInfo) { NTSTATUS Status = STATUS_SUCCESS; while (MemInfo->BaseAddress.QuadPart != 0 || MemInfo->NumberOfBytes.QuadPart != 0) { if (InSize >= sizeof(REQUEST_BUFFER) + sizeof(PHYS_MEM_REGION) * (Buff->MemMap.RegionsCount + 1)) { // copy region information to IOCTL request buffer Buff->MemMap.Regions[Buff->MemMap.RegionsCount].Address = MemInfo->BaseAddress.QuadPart; Buff->MemMap.Regions[Buff->MemMap.RegionsCount].Size = MemInfo->NumberOfBytes.QuadPart; Buff->MemMap.RegionsCount += 1; } else { Status = STATUS_UNSUCCESSFUL; break; } MemInfo += 1; MemRegion += 1; } ns = Status; } else { DbgMsg(__FILE__, __LINE__, "ERROR: MmGetPhysicalMemoryRange() fails\n"); } } break; } case DRV_CTL_PORT_READ: { // read I/O port value ns = HwPortRead(Buff->PortRead.Port, Buff->PortRead.Size, &Buff->PortRead.Val); break; } case DRV_CTL_PORT_WRITE: { // write value to I/O port ns = HwPortWrite(Buff->PortWrite.Port, Buff->PortWrite.Size, Buff->PortWrite.Val); break; } case DRV_CTL_PCI_READ: { // read PCI config space register value ns = HwPciRead(Buff->PciRead.Address, Buff->PciRead.Size, &Buff->PciRead.Val); break; } case DRV_CTL_PCI_WRITE: { // write value to PCI config space egister ns = HwPciWrite(Buff->PciWrite.Address, Buff->PciWrite.Size, Buff->PciWrite.Val); break; } case DRV_CTL_SMI_INVOKE: { // invoke SMI via APMC I/O port ns = HwSmiInvoke(Buff->SmiInvoke.Code); break; } case DRV_CTL_MEM_ALLOC: { // allocate memory if ((ns = HwMemAlloc(&Buff->MemAlloc.Address, Buff->MemAlloc.Size)) == STATUS_SUCCESS) { // get physical address by virtual ns = HwGetPhysAddr(Buff->MemAlloc.Address, &Buff->MemAlloc.PhysicalAddress); } break; } case DRV_CTL_MEM_FREE: { // free allocated memory ns = HwMemFree(Buff->MemFree.Address); break; } case DRV_CTL_PHYS_ADDR: { // get physical address by virtual ns = HwGetPhysAddr(Buff->PhysAddr.Address, &Buff->PhysAddr.PhysicalAddress); break; } case DRV_CTL_MSR_GET: { // get MSR value ns = HwMsrGet(Buff->MsrGet.Register, &Buff->MsrGet.Value); break; } case DRV_CTL_MSR_SET: { // set MSR value ns = HwMsrSet(Buff->MsrSet.Register, Buff->MsrSet.Value); break; } #ifdef USE_DSE_BYPASS case DRV_CTL_RESTORE_CR4: { // get bitmask of active processors KAFFINITY ActiveProcessors = KeQueryActiveProcessors(); ULONG cr4_val = 0, cr4_current = 0; // enumerate active processors starting from 2-nd for (KAFFINITY i = 1; i < sizeof(KAFFINITY) * 8; i++) { KAFFINITY Mask = 1 << i; if (ActiveProcessors & Mask) { // bind thread to specific processor KeSetSystemAffinityThread(Mask); // read CR4 register of other CPU cr4_val = _cr4_get(); break; } } if (cr4_val != 0) { // bind thread to first processor KeSetSystemAffinityThread(0x00000001); if ((cr4_current = _cr4_get()) != cr4_val) { DbgMsg(__FILE__, __LINE__, "Restoring CR4 value from 0x%.8x to 0x%.8x\n", cr4_current, cr4_val); // restore CR4 register of current CPU _cr4_set(cr4_val); } else { DbgMsg(__FILE__, __LINE__, "CR4 is 0x%.8x\n", cr4_current); } ns = STATUS_SUCCESS; } else { DbgMsg(__FILE__, __LINE__, "ERROR: Unable to read CR4 value from 2-nd processor\n"); } break; } #endif // USE_DSE_BYPASS default: { DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Unknown control code 0x%x\n", Code); break; } } break; } default: { break; } } } if (ns == STATUS_SUCCESS) { Irp->IoStatus.Information = InSize; } } else if (stack->MajorFunction == IRP_MJ_CREATE) { DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_CREATE\n"); ns = STATUS_SUCCESS; } else if (stack->MajorFunction == IRP_MJ_CLOSE) { DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_CLOSE\n"); ns = STATUS_SUCCESS; } if (ns != STATUS_PENDING) { Irp->IoStatus.Status = ns; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return ns; }
/* KphAcquireProcessorLock * * Raises the IRQL to DISPATCH_LEVEL and prevents threads from * executing on other processors until the processor lock is released. * Blocks if the supplied processor lock is already in use. * * ProcessorLock: A processor lock structure that is present in * non-paged memory. * * Comments: * Here is how the processor lock works: * 1. Tries to acquire the mutex in the processor lock, and * blocks until it can be obtained. * 2. Initializes a DPC for each processor on the computer. * 3. Raises the IRQL to DISPATCH_LEVEL to make sure the * code is not interrupted by a context switch. * 4. Queues each of the previously-initialized DPCs, except if * it is targeted at the current processor. * 5. Since DPCs run at DISPATCH_LEVEL, they have exclusive * control of the processor. As each runs, they increment * a counter in the processor lock. They then enter a loop. * 6. The routine waits for the counter to become n - 1, * signaling that all (other) processors have been acquired * (where n is the number of processors). * 7. It returns. Any code from here will be running in * DISPATCH_LEVEL and will be the only code running on the * machine. * Thread safety: Full * IRQL: <= APC_LEVEL */ BOOLEAN KphAcquireProcessorLock( __inout PKPH_PROCESSOR_LOCK ProcessorLock ) { ULONG i; ULONG numberProcessors; ULONG currentProcessor; /* Acquire the processor lock guarded lock. */ KphAcquireGuardedLock(&ProcessorLock->Lock); /* Reset some state. */ ASSERT(ProcessorLock->AcquiredProcessors == 0); ProcessorLock->AcquiredProcessors = 0; ProcessorLock->ReleaseSignal = 0; /* IMPORTANT */ /* Get the number of processors. */ numberProcessors = KphpCountBits(KeQueryActiveProcessors()); /* If there's only one processor we can simply raise the IRQL and exit. */ if (numberProcessors == 1) { dprintf("KphAcquireProcessorLock: Only one processor, raising IRQL and exiting...\n"); KeRaiseIrql(DISPATCH_LEVEL, &ProcessorLock->OldIrql); ProcessorLock->Acquired = TRUE; return TRUE; } /* Allocate storage for the DPCs. */ ProcessorLock->Dpcs = ExAllocatePoolWithTag( NonPagedPool, sizeof(KDPC) * numberProcessors, TAG_SYNC_DPC ); if (!ProcessorLock->Dpcs) { dprintf("KphAcquireProcessorLock: Could not allocate storage for DPCs!\n"); KphReleaseGuardedLock(&ProcessorLock->Lock); return FALSE; } /* Initialize the DPCs. */ for (i = 0; i < numberProcessors; i++) { KeInitializeDpc(&ProcessorLock->Dpcs[i], KphpProcessorLockDpc, NULL); KeSetTargetProcessorDpc(&ProcessorLock->Dpcs[i], (CCHAR)i); KeSetImportanceDpc(&ProcessorLock->Dpcs[i], HighImportance); } /* Raise the IRQL to DISPATCH_LEVEL to prevent context switching. */ KeRaiseIrql(DISPATCH_LEVEL, &ProcessorLock->OldIrql); /* Get the current processor number. */ currentProcessor = KeGetCurrentProcessorNumber(); /* Queue the DPCs (except on the current processor). */ for (i = 0; i < numberProcessors; i++) if (i != currentProcessor) KeInsertQueueDpc(&ProcessorLock->Dpcs[i], ProcessorLock, NULL); /* Spinwait for all (other) processors to be acquired. */ KphSpinUntilEqual(&ProcessorLock->AcquiredProcessors, numberProcessors - 1); dprintf("KphAcquireProcessorLock: All processors acquired.\n"); ProcessorLock->Acquired = TRUE; return TRUE; }