uint32 peChecksumExecSections(uint8 *peBaseAddr, void *realBase, PEPROCESS proc, PKAPC_STATE apc, PHYSICAL_ADDRESS *physArr) { uint16 numExecSections = peGetNumExecSections(peBaseAddr); uint32 checksum = 0, k, i, j, numRelocs = peGetNumberOfRelocs(peBaseAddr, realBase, proc, apc), relocDelta = peCalculateRelocDiff(peBaseAddr, realBase); uint8 *dataPtr = NULL; PHYSICAL_ADDRESS phys = {0}; SectionData *execSections = (SectionData *) MmAllocateNonCachedMemory( numExecSections * sizeof(SectionData)); peGetExecSections(peBaseAddr, execSections); //DbgPrint("Found %d relocations, delta of: %x\r\n", numRelocs, relocDelta); for (i = 0; i < numExecSections; i++) { uint32 numpages = execSections[i].Size / 0x1000, size = execSections[i].Size; if (numpages * 0x1000 < execSections[i].Size) numpages++; for (k = 0; k < numpages; k++) { KeStackAttachProcess(proc, apc); dataPtr = (uint8 *) MmMapIoSpace(MmGetPhysicalAddress((void *)(((uint32) realBase) + execSections[i].VirtualAddress + (0x1000 * k))), 0x1000, 0); phys = MmGetPhysicalAddress((void *) dataPtr); for (j = 0; j < min(size, 0x1000); j++) { checksum += dataPtr[j]; } MmUnmapIoSpace((void *) dataPtr, 0x1000); size -= 0x1000; KeUnstackDetachProcess(apc); } } // Subtract the relocations from the checksum // TODO Fix incase of lower load address checksum += numRelocs * (relocDelta & 0x000000FF); checksum += numRelocs * ((relocDelta & 0x0000FF00) >> 8); checksum += numRelocs * ((relocDelta & 0x00FF0000) >> 16); checksum += numRelocs * ((relocDelta & 0xFF000000) >> 24); MmFreeNonCachedMemory((void *) execSections, numExecSections * sizeof(SectionData)); return checksum; }
static struct virtqueue * FindVirtualQueue(VirtIODevice *dev, ULONG index, USHORT vector) { struct virtqueue *pq = NULL; PVOID p; ULONG size, allocSize; VirtIODeviceQueryQueueAllocation(dev, index, &size, &allocSize); if (allocSize) { PHYSICAL_ADDRESS HighestAcceptable; HighestAcceptable.QuadPart = 0xFFFFFFFFFF; p = MmAllocateContiguousMemory(allocSize, HighestAcceptable); if (p) { pq = VirtIODevicePrepareQueue(dev, index, MmGetPhysicalAddress(p), p, allocSize, p, FALSE); if (vector != VIRTIO_MSI_NO_VECTOR) { WriteVirtIODeviceWord(dev->addr + VIRTIO_MSI_QUEUE_VECTOR, vector); vector = ReadVirtIODeviceWord(dev->addr + VIRTIO_MSI_QUEUE_VECTOR); } } } return pq; }
// for risc testing purpose void HwInitProgram2(PBT878_SCREEN scr) { ULONG a=0; int l=0; PULONG code=(PULONG)scr->pCode; PULONG start=(PULONG)scr->pCodePhy; PHYSICAL_ADDRESS code_physical=MmGetPhysicalAddress(scr->pCode); ULONG start2=code_physical.u.LowPart; int i; int h=scr->ulHeight; int w=scr->ulWidth; PHYSICAL_ADDRESS frame_physical=MmGetPhysicalAddress(scr->pBuffer); ULONG frame=frame_physical.u.LowPart; // post interrupt code[l++]= RISC_JUMP | SetBin(24, "1") ; // IRQL code[l++]=(ULONG)start2; code[l++]=0; code[l++]=0; code[l++]=0; }
VOID RhelGetSerialNumber( IN PVOID DeviceExtension ) { PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; adaptExt->vbr.out_hdr.type = VIRTIO_BLK_T_GET_ID | VIRTIO_BLK_T_IN; adaptExt->vbr.out_hdr.sector = 0; adaptExt->vbr.out_hdr.ioprio = 0; adaptExt->vbr.sg[0].physAddr = MmGetPhysicalAddress(&adaptExt->vbr.out_hdr); adaptExt->vbr.sg[0].ulSize = sizeof(adaptExt->vbr.out_hdr); adaptExt->vbr.sg[1].physAddr = MmGetPhysicalAddress(&adaptExt->sn); adaptExt->vbr.sg[1].ulSize = sizeof(adaptExt->sn); adaptExt->vbr.sg[2].physAddr = MmGetPhysicalAddress(&adaptExt->vbr.status); adaptExt->vbr.sg[2].ulSize = sizeof(adaptExt->vbr.status); if (adaptExt->vq->vq_ops->add_buf(adaptExt->vq, &adaptExt->vbr.sg[0], 1, 2, &adaptExt->vbr, NULL, 0) >= 0) { adaptExt->vq->vq_ops->kick(adaptExt->vq); } }
PHYSICAL_ADDRESS XenGetPhysicalAddress( PVOID vaddr ) { return MmGetPhysicalAddress(vaddr); }
static IO_ALLOCATION_ACTION NTAPI SoundProgramDMA( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID MapRegisterBase, IN PVOID Context) { PDEVICE_EXTENSION Device = DeviceObject->DeviceExtension; ULONG zzz; PUCHAR VirtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Device->Mdl); DPRINT("IoMapTransfer\n"); IoMapTransfer(Device->Adapter, Device->Mdl, MapRegisterBase, (PUCHAR) MmGetMdlVirtualAddress(Device->Mdl), &Device->BufferSize, // is this right? TRUE); DPRINT("VBuffer == 0x%x (really 0x%x?) Bufsize == %u\n", Device->VirtualBuffer, MmGetPhysicalAddress(Device->VirtualBuffer), Device->BufferSize); DPRINT("Writing %u bytes of garbage...\n", Device->BufferSize); // Write some garbage: for (zzz = 0; zzz < Device->BufferSize; zzz ++) *(VirtualAddress + zzz) = (UCHAR) zzz % 200; DPRINT("done\n"); KeSetEvent(Context, 0, FALSE); return KeepObject; }
_Use_decl_annotations_ EXTERN_C static bool VminitpInitializeVMCS( PER_PROCESSOR_DATA *ProcessorData) { // Write a VMCS revision identifier IA32_VMX_BASIC_MSR vmxBasicMsr = {__readmsr(IA32_VMX_BASIC)}; ProcessorData->VmcsRegion->RevisionIdentifier = vmxBasicMsr.Fields.RevisionIdentifier; auto vmcsRegionPA = MmGetPhysicalAddress(ProcessorData->VmcsRegion); // It stores the value FFFFFFFF_FFFFFFFFH if there is no current VMCS if (__vmx_vmclear( reinterpret_cast<unsigned long long *>(&vmcsRegionPA.QuadPart))) { return false; } // Software makes a VMCS current by executing VMPTRLD with the address // of the VMCS; that address is loaded into the current-VMCS pointer. if (__vmx_vmptrld( reinterpret_cast<unsigned long long *>(&vmcsRegionPA.QuadPart))) { return false; } // The launch state of current VMCS is "clear" return true; }
void * platform_virt_to_phys(void *virt) { PHYSICAL_ADDRESS addr = MmGetPhysicalAddress(virt); return (void *)addr.QuadPart; }
static VOID DumpPortWrite( IN ULONG64 Offset, IN PVOID Buffer, IN ULONG Length ) { PHYSICAL_ADDRESS Address; ASSERT(Offset == (ULONG64)-1); ASSERT(IS_PAGE_ALIGNED(Buffer)); ASSERT(IS_PAGE_ALIGNED(Length)); // // Sometimes Windows passes us virtual addresses, sometimes it passes // physical addresses. It doesn't tell us which it's handing us, and // how this plays with PAE is anybody's guess. // Address = MmGetPhysicalAddress(Buffer); if (Address.QuadPart == 0) Address.QuadPart = (ULONG_PTR)Buffer; Address.QuadPart >>= PAGE_SHIFT; ASSERT3U(Address.HighPart, ==, 0); for (Length >>= PAGE_SHIFT; Length != 0; Length--) WRITE_PORT_ULONG(PortEC, Address.LowPart++); }
_Use_decl_annotations_ EXTERN_C static bool VminitpEnterVmxMode( PER_PROCESSOR_DATA *ProcessorData) { // Apply FIXED bits const CR0_REG cr0Fixed0 = {__readmsr(IA32_VMX_CR0_FIXED0)}; const CR0_REG cr0Fixed1 = {__readmsr(IA32_VMX_CR0_FIXED1)}; CR0_REG cr0 = {__readcr0()}; cr0.All &= cr0Fixed1.All; cr0.All |= cr0Fixed0.All; __writecr0(cr0.All); const CR4_REG cr4Fixed0 = {__readmsr(IA32_VMX_CR4_FIXED0)}; const CR4_REG cr4Fixed1 = {__readmsr(IA32_VMX_CR4_FIXED1)}; CR4_REG cr4 = {__readcr4()}; cr4.All &= cr4Fixed1.All; cr4.All |= cr4Fixed0.All; __writecr4(cr4.All); // Write a VMCS revision identifier IA32_VMX_BASIC_MSR vmxBasicMsr = {__readmsr(IA32_VMX_BASIC)}; ProcessorData->VmxonRegion->RevisionIdentifier = vmxBasicMsr.Fields.RevisionIdentifier; auto vmxonRegionPA = MmGetPhysicalAddress(ProcessorData->VmxonRegion); if (__vmx_on( reinterpret_cast<unsigned long long *>(&vmxonRegionPA.QuadPart))) { return false; } return true; }
static FORCEINLINE PFN_NUMBER __VirtToPfn( IN PVOID VirtAddr ) { PHYSICAL_ADDRESS PhysAddr = MmGetPhysicalAddress(VirtAddr); return (PFN_NUMBER)(ULONG_PTR)(PhysAddr.QuadPart >> 12); }
static PFN_NUMBER virt_to_pfn(void *va) { PHYSICAL_ADDRESS pa; pa = MmGetPhysicalAddress(va); return (ULONG_PTR)(pa.QuadPart >> 12); }
unsigned long co_os_virt_to_phys(void *addr) { PHYSICAL_ADDRESS pa; pa = MmGetPhysicalAddress((PVOID)addr); return pa.QuadPart; }
NTSTATUS AllocateVmxProcessorData(PVOID *VirtualAddress, PHYSICAL_ADDRESS *PhysicalAddress, SIZE_T *Size) { if (!VirtualAddress || !PhysicalAddress || !Size) return STATUS_INVALID_PARAMETER; // // Read the MSR information to get the base size // Default to 4096 bytes // VMX_BASIC_MSR msr; TO_ULL(msr) = __readmsr(MSR_IA32_VMX_BASIC); if (*Size <= 0) { // In rare cases this isn't set (*COUGH* *VMWARE*) if (msr.szVmxOnRegion > 0) *Size = msr.szVmxOnRegion; else *Size = 0x1000; *Size = ROUND_TO_PAGES(*Size); } // // Allocate CONTIGUOUS physical memory // MmCached = Stored in CPU L1/L2/L3 cache if possible // PHYSICAL_ADDRESS l1, l2, l3; l1.QuadPart = 0; l2.QuadPart = -1; l3.QuadPart = 0x200000; PVOID address = MmAllocateContiguousMemorySpecifyCache(*Size, l1, l2, l3, MmCached); if (!address) return STATUS_NO_MEMORY; RtlSecureZeroMemory(address, *Size); // // Set the revision id // *(ULONG *)address = msr.RevId; // // Done // *VirtualAddress = address; *PhysicalAddress = MmGetPhysicalAddress(address); return STATUS_SUCCESS; }
/// <summary> /// Update EPT entry /// </summary> /// <param name="pEPTData">CPU EPT data</param> /// <param name="pTable">EPT table</param> /// <param name="level">EPT table level</param> /// <param name="pfn">Page frame number to update</param> /// <param name="access">New PFN access</param> /// <param name="hostPFN">New hot PFN</param> /// <param name="count">Number of entries to update</param> /// <returns>Status code</returns> NTSTATUS EptUpdateTableRecursive( IN PEPT_DATA pEPTData, IN PEPT_MMPTE pTable, IN EPT_TABLE_LEVEL level, IN ULONG64 pfn, IN UCHAR access, IN ULONG64 hostPFN, IN ULONG count ) { if (level == EPT_LEVEL_PTE) { ULONG64 first = EptpTableOffset( pfn, level ); ASSERT( first + count <= EPT_TABLE_ENTRIES ); PEPT_PTE_ENTRY pPTE = (PEPT_PTE_ENTRY)pTable; for (ULONG64 i = first; i < first + count; i++, hostPFN++) { pPTE[i].Fields.Read = (access & EPT_ACCESS_READ) != 0; pPTE[i].Fields.Write = (access & EPT_ACCESS_WRITE) != 0; pPTE[i].Fields.Execute = (access & EPT_ACCESS_EXEC) != 0; pPTE[i].Fields.MemoryType = VMX_MEM_TYPE_WRITEBACK; pPTE[i].Fields.PhysAddr = hostPFN; } return STATUS_SUCCESS; } ULONG64 offset = EptpTableOffset( pfn, level ); PEPT_MMPTE pEPT = &pTable[offset]; PEPT_MMPTE pNewEPT = 0; if (pEPT->Fields.PhysAddr == 0) { pNewEPT = (PEPT_MMPTE)EptpAllocatePage( pEPTData ); if (pNewEPT == NULL) return STATUS_INSUFFICIENT_RESOURCES; pEPT->Fields.Present = 1; pEPT->Fields.Write = 1; pEPT->Fields.Execute = 1; pEPT->Fields.PhysAddr = PFN( MmGetPhysicalAddress( pNewEPT ).QuadPart ); } else { PHYSICAL_ADDRESS phys = { 0 }; phys.QuadPart = pEPT->Fields.PhysAddr << 12; pNewEPT = MmGetVirtualForPhysical( phys ); } return EptUpdateTableRecursive( pEPTData, pNewEPT, level - 1, pfn, access, hostPFN, count ); }
VOID RhelGetSerialNumber( IN PVOID DeviceExtension ) { ULONG QueueNumber = 0; ULONG OldIrql = 0; ULONG MessageId = 0; STOR_LOCK_HANDLE LockHandle = { 0 }; struct virtqueue *vq = NULL; PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; QueueNumber = 0; MessageId = 1; vq = adaptExt->vq[QueueNumber]; adaptExt->vbr.out_hdr.type = VIRTIO_BLK_T_GET_ID | VIRTIO_BLK_T_IN; adaptExt->vbr.out_hdr.sector = 0; adaptExt->vbr.out_hdr.ioprio = 0; adaptExt->vbr.sg[0].physAddr = MmGetPhysicalAddress(&adaptExt->vbr.out_hdr); adaptExt->vbr.sg[0].length = sizeof(adaptExt->vbr.out_hdr); adaptExt->vbr.sg[1].physAddr = MmGetPhysicalAddress(&adaptExt->sn); adaptExt->vbr.sg[1].length = sizeof(adaptExt->sn); adaptExt->vbr.sg[2].physAddr = MmGetPhysicalAddress(&adaptExt->vbr.status); adaptExt->vbr.sg[2].length = sizeof(adaptExt->vbr.status); // VioStorVQLock(DeviceExtension, MessageId, &LockHandle, FALSE); if (virtqueue_add_buf(vq, &adaptExt->vbr.sg[0], 1, 2, &adaptExt->vbr, NULL, 0) >= 0) { #ifdef DBG InterlockedIncrement((LONG volatile*)&adaptExt->inqueue_cnt); #endif virtqueue_kick_always(vq); } // VioStorVQUnlock(DeviceExtension, MessageId, &LockHandle, FALSE); }
size_t VIOSerialSendBuffers(IN PVIOSERIAL_PORT Port, IN PVOID Buffer, IN size_t Length) { struct virtqueue *vq = GetOutQueue(Port); struct VirtIOBufferDescriptor sg[QUEUE_DESCRIPTORS]; PVOID buffer = Buffer; size_t length = Length; int out = 0; int ret; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> %s Buffer: %p Length: %d\n", __FUNCTION__, Buffer, Length); if (BYTES_TO_PAGES(Length) > QUEUE_DESCRIPTORS) { return 0; } while (length > 0) { sg[out].physAddr = MmGetPhysicalAddress(buffer); sg[out].length = min(length, PAGE_SIZE); buffer = (PVOID)((LONG_PTR)buffer + sg[out].length); length -= sg[out].length; out += 1; } WdfSpinLockAcquire(Port->OutVqLock); ret = virtqueue_add_buf(vq, sg, out, 0, Buffer, NULL, 0); virtqueue_kick(vq); if (ret >= 0) { Port->OutVqFull = (ret == 0); } else { Length = 0; TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Error adding buffer to queue (ret = %d)\n", ret); } WdfSpinLockRelease(Port->OutVqLock); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- %s\n", __FUNCTION__); return Length; }
VOID VIOSerialSendCtrlMsg( IN WDFDEVICE Device, IN ULONG id, IN USHORT event, IN USHORT value ) { struct VirtIOBufferDescriptor sg; struct virtqueue *vq; UINT len; PPORTS_DEVICE pContext = GetPortsDevice(Device); VIRTIO_CONSOLE_CONTROL cpkt; int cnt = 0; if (!pContext->isHostMultiport) { return; } vq = pContext->c_ovq; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s vq = %p\n", __FUNCTION__, vq); cpkt.id = id; cpkt.event = event; cpkt.value = value; sg.physAddr = MmGetPhysicalAddress(&cpkt); sg.ulSize = sizeof(cpkt); WdfSpinLockAcquire(pContext->CVqLock); if(0 <= vq->vq_ops->add_buf(vq, &sg, 1, 0, &cpkt, NULL, 0)) { vq->vq_ops->kick(vq); while(!vq->vq_ops->get_buf(vq, &len)) { KeStallExecutionProcessor(50); if(++cnt > RETRY_THRESHOLD) { TraceEvents(TRACE_LEVEL_FATAL, DBG_PNP, "<-> %s retries = %d\n", __FUNCTION__, cnt); break; } } } WdfSpinLockRelease(pContext->CVqLock); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s cnt = %d\n", __FUNCTION__, cnt); }
VOID VIOSerialSendCtrlMsg( IN WDFDEVICE Device, IN ULONG id, IN USHORT event, IN USHORT value ) { struct VirtIOBufferDescriptor sg; struct virtqueue *vq; UINT len; PPORTS_DEVICE pContext = GetPortsDevice(Device); VIRTIO_CONSOLE_CONTROL cpkt; if (!pContext->isHostMultiport) { return; } vq = pContext->c_ovq; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s vq = %p\n", __FUNCTION__, vq); cpkt.id = id; cpkt.event = event; cpkt.value = value; sg.physAddr = MmGetPhysicalAddress(&cpkt); sg.length = sizeof(cpkt); WdfWaitLockAcquire(pContext->COutVqLock, NULL); if(0 <= virtqueue_add_buf(vq, &sg, 1, 0, &cpkt, NULL, 0)) { virtqueue_kick(vq); while(!virtqueue_get_buf(vq, &len)) { LARGE_INTEGER interval; interval.QuadPart = -1; KeDelayExecutionThread(KernelMode, FALSE, &interval); } } WdfWaitLockRelease(pContext->COutVqLock); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__); }
static PVIOQUEUE FindVirtualQueue(VIODEVICE *dev, ULONG index) { PVIOQUEUE pq = NULL; PVOID p; ULONG size, allocSize; VirtIODeviceQueryQueueAllocation(dev, index, &size, &allocSize); if (allocSize) { PHYSICAL_ADDRESS HighestAcceptable; HighestAcceptable.QuadPart = 0xFFFFFFFFFF; p = MmAllocateContiguousMemory(allocSize, HighestAcceptable); if (p) { pq = VirtIODevicePrepareQueue(dev, index, MmGetPhysicalAddress(p), p, allocSize, p, FALSE); } } return pq; }
ACPI_STATUS AcpiOsGetPhysicalAddress( void *LogicalAddress, ACPI_PHYSICAL_ADDRESS *PhysicalAddress) { PHYSICAL_ADDRESS PhysAddr; if (!LogicalAddress || !PhysicalAddress) { DPRINT1("Bad parameter\n"); return AE_BAD_PARAMETER; } PhysAddr = MmGetPhysicalAddress(LogicalAddress); *PhysicalAddress = (ACPI_PHYSICAL_ADDRESS)PhysAddr.QuadPart; return AE_OK; }
VOID BalloonMemStats( IN WDFOBJECT WdfDevice ) { VIO_SG sg; PDEVICE_CONTEXT devCtx = GetDeviceContext(WdfDevice); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__); sg.physAddr = MmGetPhysicalAddress(devCtx->MemStats); sg.ulSize = sizeof(BALLOON_STAT) * VIRTIO_BALLOON_S_NR; if(devCtx->StatVirtQueue->vq_ops->add_buf(devCtx->StatVirtQueue, &sg, 1, 0, devCtx, NULL, 0) < 0) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "<-> %s :: Cannot add buffer\n", __FUNCTION__); } devCtx->StatVirtQueue->vq_ops->kick(devCtx->StatVirtQueue); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__); }
/** * Allocates physical contiguous memory (below 4GB). * The allocation is page aligned and its contents is undefined. * * @returns Pointer to the memory block. This is page aligned. * @param pPhys Where to store the physical address. * @param cb The allocation size in bytes. This is always * rounded up to PAGE_SIZE. */ RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb) { /* * validate input. */ Assert(VALID_PTR(pPhys)); Assert(cb > 0); /* * Allocate and get physical address. * Make sure the return is page aligned. */ PHYSICAL_ADDRESS MaxPhysAddr; MaxPhysAddr.HighPart = 0; MaxPhysAddr.LowPart = 0xffffffff; cb = RT_ALIGN_Z(cb, PAGE_SIZE); void *pv = MmAllocateContiguousMemory(cb, MaxPhysAddr); if (pv) { if (!((uintptr_t)pv & PAGE_OFFSET_MASK)) /* paranoia */ { PHYSICAL_ADDRESS PhysAddr = MmGetPhysicalAddress(pv); if (!PhysAddr.HighPart) /* paranoia */ { *pPhys = (RTCCPHYS)PhysAddr.LowPart; return pv; } /* failure */ AssertMsgFailed(("MMAllocContiguousMemory returned high address! PhysAddr=%RX64\n", (uint64_t)PhysAddr.QuadPart)); } else AssertMsgFailed(("MMAllocContiguousMemory didn't return a page aligned address - %p!\n", pv)); MmFreeContiguousMemory(pv); } return NULL; }
PPORT_BUFFER VIOSerialAllocateBuffer( IN size_t buf_size ) { PPORT_BUFFER buf; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_QUEUEING, "--> %s\n", __FUNCTION__); buf = ExAllocatePoolWithTag( NonPagedPool, sizeof(PORT_BUFFER), VIOSERIAL_DRIVER_MEMORY_TAG ); if (buf == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_QUEUEING, "ExAllocatePoolWithTag failed, %s::%d\n", __FUNCTION__, __LINE__); return NULL; } buf->va_buf = ExAllocatePoolWithTag( NonPagedPool, buf_size, VIOSERIAL_DRIVER_MEMORY_TAG ); if(buf->va_buf == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_QUEUEING, "ExAllocatePoolWithTag failed, %s::%d\n", __FUNCTION__, __LINE__); ExFreePoolWithTag(buf, VIOSERIAL_DRIVER_MEMORY_TAG); return NULL; } buf->pa_buf = MmGetPhysicalAddress(buf->va_buf); buf->len = 0; buf->offset = 0; buf->size = buf_size; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_QUEUEING, "<-- %s\n", __FUNCTION__); return buf; }
STDMETHODIMP_(NTSTATUS) CDmaChannel::AllocateBuffer(ULONG newBufferSize, PPHYSICAL_ADDRESS constraint OPTIONAL) { // free current buffer FreeBuffer(); // re-allocate buffer = MmAllocateContiguousMemory(newBufferSize,*constraint); if(buffer) { allocatedSize=newBufferSize; bufferSize=newBufferSize; physicalBufstart=MmGetPhysicalAddress(buffer); return STATUS_SUCCESS; } else { debug(DWDM,"!! CDmaChannel::AllocateBuffer: could not re-allocate buffer (%d->%d)\n",allocatedSize,bufferSize); allocatedSize=0; bufferSize=0; return STATUS_INSUFFICIENT_RESOURCES; } }
VOID BalloonTellHost( IN WDFOBJECT WdfDevice, IN PVIOQUEUE vq ) { VIO_SG sg; PDEVICE_CONTEXT devCtx = GetDeviceContext(WdfDevice); NTSTATUS status; LARGE_INTEGER timeout = {0}; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__); sg.physAddr = MmGetPhysicalAddress(devCtx->pfns_table); sg.ulSize = sizeof(devCtx->pfns_table[0]) * devCtx->num_pfns; if(vq->vq_ops->add_buf(vq, &sg, 1, 0, devCtx, NULL, 0) < 0) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "<-> %s :: Cannot add buffer\n", __FUNCTION__); return; } vq->vq_ops->kick(vq); timeout.QuadPart = Int32x32To64(1000, -10000); status = KeWaitForSingleObject ( &devCtx->HostAckEvent, Executive, KernelMode, FALSE, &timeout); ASSERT(NT_SUCCESS(status)); if(STATUS_TIMEOUT == status) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "<--> TimeOut\n"); } }
VOID DumpQueueHeadList(PEHCI_HOST_CONTROLLER hcd) { KIRQL OldIrql; KeAcquireSpinLock(&hcd->Lock, &OldIrql); PQUEUE_HEAD QueueHead = (PQUEUE_HEAD)hcd->CommonBufferVA; PQUEUE_HEAD FirstQueueHead = QueueHead; DPRINT1("Dumping QueueHead List!!!!!!!!!!!!!\n"); while (1) { DPRINT1("QueueHead Address %x\n", QueueHead); DPRINT1("QueueHead->PreviousQueueHead = %x\n", QueueHead->PreviousQueueHead); DPRINT1("QueueHead->NextQueueHead = %x\n", QueueHead->NextQueueHead); DPRINT1(" ---> PhysicalAddress %x\n", (ULONG)MmGetPhysicalAddress(QueueHead).LowPart); DPRINT1("QueueHead->HorizontalLinkPointer %x\n", QueueHead->HorizontalLinkPointer); QueueHead = QueueHead->NextQueueHead; DPRINT1("Next QueueHead %x\n", QueueHead); if (QueueHead == FirstQueueHead) break; } DPRINT1("-----------------------------------\n"); KeReleaseSpinLock(&hcd->Lock, OldIrql); }
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
_Use_decl_annotations_ EXTERN_C static bool VminitpSetupVMCS( const PER_PROCESSOR_DATA *ProcessorData, ULONG_PTR GuestStackPointer, ULONG_PTR GuestInstructionPointer, ULONG_PTR VmmStackPointer) { unsigned char error = 0; GDTR gdtr = {}; __sgdt(&gdtr); IDTR idtr = {}; __sidt(&idtr); VMX_VM_ENTER_CONTROLS vmEnterCtlRequested = {}; vmEnterCtlRequested.Fields.IA32eModeGuest = true; VMX_VM_ENTER_CONTROLS vmEnterCtl = { VminitpAdjustControlValue(IA32_VMX_ENTRY_CTLS, vmEnterCtlRequested.All)}; VMX_VM_EXIT_CONTROLS vmExitCtlRequested = {}; vmExitCtlRequested.Fields.AcknowledgeInterruptOnExit = true; vmExitCtlRequested.Fields.HostAddressSpaceSize = true; VMX_VM_EXIT_CONTROLS vmExitCtl = { VminitpAdjustControlValue(IA32_VMX_EXIT_CTLS, vmExitCtlRequested.All)}; VMX_PIN_BASED_CONTROLS vmPinCtlRequested = {}; VMX_PIN_BASED_CONTROLS vmPinCtl = { VminitpAdjustControlValue(IA32_VMX_PINBASED_CTLS, vmPinCtlRequested.All)}; VMX_CPU_BASED_CONTROLS vmCpuCtlRequested = {}; vmCpuCtlRequested.Fields.RDTSCExiting = true; vmCpuCtlRequested.Fields.CR3LoadExiting = true; // MOV to CR3 vmCpuCtlRequested.Fields.CR8LoadExiting = true; // MOV to CR8 vmCpuCtlRequested.Fields.MovDRExiting = true; vmCpuCtlRequested.Fields.UseMSRBitmaps = true; vmCpuCtlRequested.Fields.ActivateSecondaryControl = true; VMX_CPU_BASED_CONTROLS vmCpuCtl = {VminitpAdjustControlValue( IA32_VMX_PROCBASED_CTLS, vmCpuCtlRequested.All)}; VMX_SECONDARY_CPU_BASED_CONTROLS vmCpuCtl2Requested = {}; vmCpuCtl2Requested.Fields.EnableRDTSCP = true; vmCpuCtl2Requested.Fields.DescriptorTableExiting = true; VMX_CPU_BASED_CONTROLS vmCpuCtl2 = {VminitpAdjustControlValue( IA32_VMX_PROCBASED_CTLS2, vmCpuCtl2Requested.All)}; // Set up the MSR bitmap // Activate VM-exit for RDMSR against all MSRs const auto bitMapReadLow = reinterpret_cast<UCHAR *>(ProcessorData->MsrBitmap); const auto bitMapReadHigh = bitMapReadLow + 1024; RtlFillMemory(bitMapReadLow, 1024, 0xff); // read 0 - 1fff RtlFillMemory(bitMapReadHigh, 1024, 0xff); // read c0000000 - c0001fff // But ignore IA32_MPERF (000000e7) and IA32_APERF (000000e8) RTL_BITMAP bitMapReadLowHeader = {}; RtlInitializeBitMap(&bitMapReadLowHeader, reinterpret_cast<PULONG>(bitMapReadLow), 1024 * 8); RtlClearBits(&bitMapReadLowHeader, 0xe7, 2); // But ignore IA32_GS_BASE (c0000101) and IA32_KERNEL_GS_BASE (c0000102) RTL_BITMAP bitMapReadHighHeader = {}; RtlInitializeBitMap(&bitMapReadHighHeader, reinterpret_cast<PULONG>(bitMapReadHigh), 1024 * 8); RtlClearBits(&bitMapReadHighHeader, 0x101, 2); const auto msrBitmapPA = MmGetPhysicalAddress(ProcessorData->MsrBitmap); // Set up CR0 and CR4 bitmaps // Where a bit is masked, the shadow bit appears // Where a bit is not masked, the actual bit appears CR0_REG cr0mask = {}; cr0mask.Fields.WP = true; CR4_REG cr4mask = {}; cr4mask.Fields.PGE = true; // clang-format off /* 16-Bit Control Field */ /* 16-Bit Guest-State Fields */ error |= __vmx_vmwrite(GUEST_ES_SELECTOR, AsmReadES()); error |= __vmx_vmwrite(GUEST_CS_SELECTOR, AsmReadCS()); error |= __vmx_vmwrite(GUEST_SS_SELECTOR, AsmReadSS()); error |= __vmx_vmwrite(GUEST_DS_SELECTOR, AsmReadDS()); error |= __vmx_vmwrite(GUEST_FS_SELECTOR, AsmReadFS()); error |= __vmx_vmwrite(GUEST_GS_SELECTOR, AsmReadGS()); error |= __vmx_vmwrite(GUEST_LDTR_SELECTOR, AsmReadLDTR()); error |= __vmx_vmwrite(GUEST_TR_SELECTOR, AsmReadTR()); /* 16-Bit Host-State Fields */ error |= __vmx_vmwrite(HOST_ES_SELECTOR, AsmReadES() & 0xf8); // RPL and TI error |= __vmx_vmwrite(HOST_CS_SELECTOR, AsmReadCS() & 0xf8); // have to be 0 error |= __vmx_vmwrite(HOST_SS_SELECTOR, AsmReadSS() & 0xf8); error |= __vmx_vmwrite(HOST_DS_SELECTOR, AsmReadDS() & 0xf8); error |= __vmx_vmwrite(HOST_FS_SELECTOR, AsmReadFS() & 0xf8); error |= __vmx_vmwrite(HOST_GS_SELECTOR, AsmReadGS() & 0xf8); error |= __vmx_vmwrite(HOST_TR_SELECTOR, AsmReadTR() & 0xf8); /* 64-Bit Control Fields */ error |= __vmx_vmwrite(IO_BITMAP_A, 0); error |= __vmx_vmwrite(IO_BITMAP_B, 0); error |= __vmx_vmwrite(MSR_BITMAP, msrBitmapPA.QuadPart); error |= __vmx_vmwrite(TSC_OFFSET, 0); /* 64-Bit Guest-State Fields */ error |= __vmx_vmwrite(VMCS_LINK_POINTER, 0xffffffffffffffff); error |= __vmx_vmwrite(GUEST_IA32_DEBUGCTL, __readmsr(IA32_DEBUGCTL)); /* 32-Bit Control Fields */ error |= __vmx_vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmPinCtl.All); error |= __vmx_vmwrite(CPU_BASED_VM_EXEC_CONTROL, vmCpuCtl.All); error |= __vmx_vmwrite(SECONDARY_VM_EXEC_CONTROL, vmCpuCtl2.All); error |= __vmx_vmwrite(EXCEPTION_BITMAP, 0); error |= __vmx_vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0); error |= __vmx_vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0); error |= __vmx_vmwrite(CR3_TARGET_COUNT, 0); error |= __vmx_vmwrite(VM_EXIT_CONTROLS, vmExitCtl.All); error |= __vmx_vmwrite(VM_EXIT_MSR_STORE_COUNT, 0); error |= __vmx_vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0); error |= __vmx_vmwrite(VM_ENTRY_CONTROLS, vmEnterCtl.All); error |= __vmx_vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0); error |= __vmx_vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0); /* 32-Bit Guest-State Fields */ error |= __vmx_vmwrite(GUEST_ES_LIMIT, GetSegmentLimit(AsmReadES())); error |= __vmx_vmwrite(GUEST_CS_LIMIT, GetSegmentLimit(AsmReadCS())); error |= __vmx_vmwrite(GUEST_SS_LIMIT, GetSegmentLimit(AsmReadSS())); error |= __vmx_vmwrite(GUEST_DS_LIMIT, GetSegmentLimit(AsmReadDS())); error |= __vmx_vmwrite(GUEST_FS_LIMIT, GetSegmentLimit(AsmReadFS())); error |= __vmx_vmwrite(GUEST_GS_LIMIT, GetSegmentLimit(AsmReadGS())); error |= __vmx_vmwrite(GUEST_LDTR_LIMIT, GetSegmentLimit(AsmReadLDTR())); error |= __vmx_vmwrite(GUEST_TR_LIMIT, GetSegmentLimit(AsmReadTR())); error |= __vmx_vmwrite(GUEST_GDTR_LIMIT, gdtr.Limit); error |= __vmx_vmwrite(GUEST_IDTR_LIMIT, idtr.Limit); error |= __vmx_vmwrite(GUEST_ES_AR_BYTES, VminitpGetSegmentAccessRight(AsmReadES())); error |= __vmx_vmwrite(GUEST_CS_AR_BYTES, VminitpGetSegmentAccessRight(AsmReadCS())); error |= __vmx_vmwrite(GUEST_SS_AR_BYTES, VminitpGetSegmentAccessRight(AsmReadSS())); error |= __vmx_vmwrite(GUEST_DS_AR_BYTES, VminitpGetSegmentAccessRight(AsmReadDS())); error |= __vmx_vmwrite(GUEST_FS_AR_BYTES, VminitpGetSegmentAccessRight(AsmReadFS())); error |= __vmx_vmwrite(GUEST_GS_AR_BYTES, VminitpGetSegmentAccessRight(AsmReadGS())); error |= __vmx_vmwrite(GUEST_LDTR_AR_BYTES, VminitpGetSegmentAccessRight(AsmReadLDTR())); error |= __vmx_vmwrite(GUEST_TR_AR_BYTES, VminitpGetSegmentAccessRight(AsmReadTR())); error |= __vmx_vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); error |= __vmx_vmwrite(GUEST_ACTIVITY_STATE, 0); error |= __vmx_vmwrite(GUEST_SYSENTER_CS, __readmsr(IA32_SYSENTER_CS)); /* 32-Bit Host-State Field */ error |= __vmx_vmwrite(HOST_IA32_SYSENTER_CS, __readmsr(IA32_SYSENTER_CS)); /* Natural-Width Control Fields */ error |= __vmx_vmwrite(CR0_GUEST_HOST_MASK, cr0mask.All); error |= __vmx_vmwrite(CR4_GUEST_HOST_MASK, cr4mask.All); error |= __vmx_vmwrite(CR0_READ_SHADOW, __readcr0()); error |= __vmx_vmwrite(CR4_READ_SHADOW, __readcr4()); error |= __vmx_vmwrite(CR3_TARGET_VALUE0, 0); error |= __vmx_vmwrite(CR3_TARGET_VALUE1, 0); error |= __vmx_vmwrite(CR3_TARGET_VALUE2, 0); error |= __vmx_vmwrite(CR3_TARGET_VALUE3, 0); /* Natural-Width Guest-State Fields */ error |= __vmx_vmwrite(GUEST_CR0, __readcr0()); error |= __vmx_vmwrite(GUEST_CR3, __readcr3()); error |= __vmx_vmwrite(GUEST_CR4, __readcr4()); error |= __vmx_vmwrite(GUEST_ES_BASE, 0); error |= __vmx_vmwrite(GUEST_CS_BASE, 0); error |= __vmx_vmwrite(GUEST_SS_BASE, 0); error |= __vmx_vmwrite(GUEST_DS_BASE, 0); error |= __vmx_vmwrite(GUEST_FS_BASE, __readmsr(IA32_FS_BASE)); error |= __vmx_vmwrite(GUEST_GS_BASE, __readmsr(IA32_GS_BASE)); error |= __vmx_vmwrite(GUEST_LDTR_BASE, VminitpGetSegmentBase(gdtr.Address, AsmReadLDTR())); error |= __vmx_vmwrite(GUEST_TR_BASE, VminitpGetSegmentBase(gdtr.Address, AsmReadTR())); error |= __vmx_vmwrite(GUEST_GDTR_BASE, gdtr.Address); error |= __vmx_vmwrite(GUEST_IDTR_BASE, idtr.Address); error |= __vmx_vmwrite(GUEST_DR7, __readdr(7)); error |= __vmx_vmwrite(GUEST_RSP, GuestStackPointer); error |= __vmx_vmwrite(GUEST_RIP, GuestInstructionPointer); error |= __vmx_vmwrite(GUEST_RFLAGS, __readeflags()); error |= __vmx_vmwrite(GUEST_SYSENTER_ESP, __readmsr(IA32_SYSENTER_ESP)); error |= __vmx_vmwrite(GUEST_SYSENTER_EIP, __readmsr(IA32_SYSENTER_EIP)); /* Natural-Width Host-State Fields */ error |= __vmx_vmwrite(HOST_CR0, __readcr0()); error |= __vmx_vmwrite(HOST_CR3, __readcr3()); error |= __vmx_vmwrite(HOST_CR4, __readcr4()); error |= __vmx_vmwrite(HOST_FS_BASE, __readmsr(IA32_FS_BASE)); error |= __vmx_vmwrite(HOST_GS_BASE, __readmsr(IA32_GS_BASE)); error |= __vmx_vmwrite(HOST_TR_BASE, VminitpGetSegmentBase(gdtr.Address, AsmReadTR())); error |= __vmx_vmwrite(HOST_GDTR_BASE, gdtr.Address); error |= __vmx_vmwrite(HOST_IDTR_BASE, idtr.Address); error |= __vmx_vmwrite(HOST_IA32_SYSENTER_ESP, __readmsr(IA32_SYSENTER_ESP)); error |= __vmx_vmwrite(HOST_IA32_SYSENTER_EIP, __readmsr(IA32_SYSENTER_EIP)); error |= __vmx_vmwrite(HOST_RSP, VmmStackPointer); error |= __vmx_vmwrite(HOST_RIP, reinterpret_cast<size_t>(AsmVmmEntryPoint)); // clang-format on const auto vmxStatus = static_cast<VMX_STATUS>(error); return vmxStatus == VMX_OK; }
// This runs at a lower IRQL, so it can use the kernel memory functions void processCreationMonitor(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create) { PEPROCESS proc = NULL; void *PeHeaderVirt = NULL; uint16 numExecSections = 0; uint8 *pePtr = NULL; PHYSICAL_ADDRESS phys = {0}; char *procName; uint32 imageSize, translations = (uint32) translationArr; NTSTATUS status = STATUS_SUCCESS; HANDLE periodMeasureThreadHandle = NULL; OBJECT_ATTRIBUTES objectAttributes = {0}; // Set to anywhere inthe 4GB range highestMemoryAddress.LowPart = ~0; // Get the 8.3 image name PsLookupProcessByProcessId(ProcessId, &proc); procName = PsGetProcessImageFileName(proc); // Check if this is the target process if(strncmp(TargetAppName, procName, strlen(TargetAppName)) == 0) { if (Create && VDEBUG) DbgPrint("New Process Created! %s\r\n", procName); if (!Create && VDEBUG) DbgPrint("Application quitting %s\r\n", procName); // Retrieve virtual pointer to the PE header for target application (in PE context) PeHeaderVirt = PsGetProcessSectionBaseAddress(proc); //DbgPrint("Virt: %x", PeHeaderVirt); // Begin critical section // Attach to the target process and grab its CR3 value to use later KeStackAttachProcess(proc, &apcstate); if (Create) { __asm { push eax mov eax, cr3 mov targetCR3, eax pop eax } } phys = MmGetPhysicalAddress(PeHeaderVirt); KeUnstackDetachProcess(&apcstate); // End critical section targetPePhys = phys; targetPeVirt = PeHeaderVirt; targetProc = proc; if (Create) { targetPePtr = peMapInImageHeader(phys); imageSize = peGetImageSize(targetPePtr); if (VDEBUG) DbgPrint("Image Size: %x bytes Num Entries %d\r\n", imageSize, sizeof(TlbTranslation) * (imageSize / PAGE_SIZE)); DbgPrint("Virt %x - %x %x\r\n", PeHeaderVirt, (uint32) PeHeaderVirt + imageSize, targetCR3); // Ensure Windows doesn't reuse the physical pages LockedMdl = pagingLockProcessMemory(PeHeaderVirt, imageSize, proc, &apcstate); if(LockedMdl == NULL && VDEBUG) { DbgPrint("Unable to lock memory\r\n"); } appsize = imageSize; appCopy = (uint8 *) MmAllocateContiguousMemory(imageSize, highestMemoryAddress); RtlZeroMemory((void *) appCopy, imageSize); copyPe(proc, &apcstate, PeHeaderVirt, appCopy, imageSize); translationArr = allocateAndFillTranslationArray(PeHeaderVirt, appCopy, imageSize, proc, &apcstate); translations = (uint32) translationArr; // VMCALL to start the TLB splitting __asm { PUSHAD MOV EAX, VMCALL_INIT_SPLIT MOV EBX, translations _emit 0x0F // VMCALL _emit 0x01 _emit 0xC1 POPAD } if (VDEBUG) DbgPrint("Checksum of proc: %x\r\n", peChecksumExecSections(targetPePtr, PeHeaderVirt, proc, &apcstate, targetPhys)); //pePrintSections(pePtr); #ifdef PERIODIC_MEASURE /* Set up periodic measurement thread */ KeInitializeEvent(&periodicMeasureThreadWakeUp, NotificationEvent, FALSE); //returns void InitializeObjectAttributes(&objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); //returns void periodicMeasureThreadExecute = 1; //allows thread to execute status = PsCreateSystemThread(&periodMeasureThreadHandle, THREAD_ALL_ACCESS, &objectAttributes, NULL, NULL, periodicMeasurePe, NULL); status = ObReferenceObjectByHandle(periodMeasureThreadHandle, 0, NULL, KernelMode, &periodicMeasureThread, NULL); ZwClose(periodMeasureThreadHandle); //don't need the handle anymore, ref will remain valid #endif } else { translations = (uint32) translationArr; // VMCALL to stop TLB splitting __asm { PUSHAD MOV EAX, VMCALL_END_SPLIT MOV EBX, translations _emit 0x0F // VMCALL _emit 0x01 _emit 0xC1 POPAD } if (LockedMdl != NULL) { pagingUnlockProcessMemory(proc, &apcstate, LockedMdl); } if (appCopy != NULL) { MmFreeContiguousMemory((PVOID) appCopy); } if (translationArr != NULL) { freeTranslationArray(translationArr); } targetCR3 = 0; #ifdef PERIODIC_MEASURE /* Stop the periodic measurement thread */ periodicMeasureThreadExecute = 0; // Apply brakes KeSetEvent(&periodicMeasureThreadWakeUp, 0, TRUE); // Cancel any current wait in the thread /* Wait for thread to stop */ KeWaitForSingleObject(periodicMeasureThread, Executive, KernelMode, FALSE, NULL); ObDereferenceObject(periodicMeasureThread); #endif peMapOutImageHeader(targetPePtr); targetPeVirt = NULL; } return; }