PVOID MmDbgTranslatePhysicalAddress ( IN PHYSICAL_ADDRESS PhysicalAddress ) /*++ Routine Description: ALPHA implementation specific: This routine maps the specified physical address and returns the virtual address which maps the physical address. The next call to MmDbgTranslatePhyiscalAddress removes the previous phyiscal address translation, hence on a single physical address can be examined at a time (can't cross page boundaries). Arguments: PhysicalAddress - Supplies the phyiscal address to map and translate. Return Value: The virtual address which corresponds to the phyiscal address. Environment: Kernel mode IRQL at DISPATCH_LEVEL or greater. --*/ { PVOID BaseAddress; LARGE_INTEGER LiTmp; BaseAddress = MiGetVirtualAddressMappedByPte (MmDebugPte); KiFlushSingleTb (TRUE, BaseAddress); *MmDebugPte = ValidKernelPte; LiTmp.QuadPart = PhysicalAddress.QuadPart >> PAGE_SHIFT; MmDebugPte->u.Hard.PageFrameNumber = LiTmp.LowPart; return (PVOID)((ULONG)BaseAddress + BYTE_OFFSET(PhysicalAddress.LowPart)); }
DECLSPEC_NOINLINE VOID KiIpiProcessRequests ( VOID ) /*++ Routine Description: This routine processes interprocessor requests and returns a summary of the requests that were processed. Arguments: None. Return Value: None. --*/ { #if !defined(NT_UP) PVOID *End; ULONG64 Number; PKPRCB Packet; PKPRCB Prcb; ULONG Processor; REQUEST_SUMMARY Request; PREQUEST_MAILBOX RequestMailbox; PKREQUEST_PACKET RequestPacket; LONG64 SetMember; PKPRCB Source; KAFFINITY SummarySet; KAFFINITY TargetSet; PVOID *Virtual; // // Loop until the sender summary is zero. // Prcb = KeGetCurrentPrcb(); TargetSet = ReadForWriteAccess(&Prcb->SenderSummary); SetMember = Prcb->SetMember; while (TargetSet != 0) { SummarySet = TargetSet; BitScanForward64(&Processor, SummarySet); do { Source = KiProcessorBlock[Processor]; RequestMailbox = &Prcb->RequestMailbox[Processor]; Request.Summary = RequestMailbox->RequestSummary; // // If the request type is flush multiple immediate, flush process, // flush single, or flush all, then packet done can be signaled // before processing the request. Otherwise, the request type must // be a packet request, a cache invalidate, or a flush multiple // if (Request.IpiRequest <= IPI_FLUSH_ALL) { // // If the synchronization type is target set, then the IPI was // only between two processors and target set should be used // for synchronization. Otherwise, packet barrier is used for // synchronization. // if (Request.IpiSynchType == 0) { if (SetMember == InterlockedXor64((PLONG64)&Source->TargetSet, SetMember)) { Source->PacketBarrier = 0; } } else { Source->TargetSet = 0; } if (Request.IpiRequest == IPI_FLUSH_MULTIPLE_IMMEDIATE) { Number = Request.Count; Virtual = &RequestMailbox->Virtual[0]; End = Virtual + Number; do { KiFlushSingleTb(*Virtual); Virtual += 1; } while (Virtual < End); } else if (Request.IpiRequest == IPI_FLUSH_PROCESS) { KiFlushProcessTb(); } else if (Request.IpiRequest == IPI_FLUSH_SINGLE) { KiFlushSingleTb((PVOID)Request.Parameter); } else { ASSERT(Request.IpiRequest == IPI_FLUSH_ALL); KeFlushCurrentTb(); } } else { // // If the request type is packet ready, then call the worker // function. Otherwise, the request must be either a flush // multiple or a cache invalidate. // if (Request.IpiRequest == IPI_PACKET_READY) { Packet = Source; if (Request.IpiSynchType != 0) { Packet = (PKPRCB)((ULONG64)Source + 1); } RequestPacket = (PKREQUEST_PACKET)&RequestMailbox->RequestPacket; (RequestPacket->WorkerRoutine)((PKIPI_CONTEXT)Packet, RequestPacket->CurrentPacket[0], RequestPacket->CurrentPacket[1], RequestPacket->CurrentPacket[2]); } else { if (Request.IpiRequest == IPI_FLUSH_MULTIPLE) { Number = Request.Count; Virtual = (PVOID *)Request.Parameter; End = Virtual + Number; do { KiFlushSingleTb(*Virtual); Virtual += 1; } while (Virtual < End); } else if (Request.IpiRequest == IPI_INVALIDATE_ALL) { WritebackInvalidate(); } else { ASSERT(FALSE); } // // If the synchronization type is target set, then the IPI was // only between two processors and target set should be used // for synchronization. Otherwise, packet barrier is used for // synchronization. // if (Request.IpiSynchType == 0) { if (SetMember == InterlockedXor64((PLONG64)&Source->TargetSet, SetMember)) { Source->PacketBarrier = 0; } } else { Source->TargetSet = 0; } } } SummarySet ^= AFFINITY_MASK(Processor); } while (BitScanForward64(&Processor, SummarySet) != FALSE); // // Clear target set in sender summary. // TargetSet = InterlockedExchangeAdd64((LONG64 volatile *)&Prcb->SenderSummary, -(LONG64)TargetSet) - TargetSet; } #endif return; }
VOID KeFlushMultipleTb ( IN ULONG Number, IN PVOID *Virtual, IN BOOLEAN AllProcessors ) /*++ Routine Description: This function flushes multiple entries from the translation buffer on all processors that are currently running threads which are children of the current process or flushes a multiple entries from the translation buffer on all processors in the host configuration. Arguments: Number - Supplies the number of TB entries to flush. Virtual - Supplies a pointer to an array of virtual addresses that are within the pages whose translation buffer entries are to be flushed. AllProcessors - Supplies a boolean value that determines which translation buffers are to be flushed. Return Value: The previous contents of the specified page table entry is returned as the function value. --*/ { PKAFFINITY Barrier; PVOID *End; KIRQL OldIrql; PKPRCB Prcb; PKPROCESS Process; KAFFINITY TargetProcessors; ASSERT((Number != 0) && (Number <= FLUSH_MULTIPLE_MAXIMUM)); // // Compute target set of processors. // OldIrql = KeRaiseIrqlToSynchLevel(); Prcb = KeGetCurrentPrcb(); if (AllProcessors != FALSE) { TargetProcessors = KeActiveProcessors; } else { Process = Prcb->CurrentThread->ApcState.Process; TargetProcessors = Process->ActiveProcessors; } // // Send request to target processors, if any, flush multiple entries in // current TB, and wait for the IPI request barrier. // End = Virtual + Number; TargetProcessors &= ~Prcb->SetMember; if (TargetProcessors != 0) { Barrier = KiIpiSendRequest(TargetProcessors, (LONG64)Virtual, Number, IPI_FLUSH_MULTIPLE); do { KiFlushSingleTb(*Virtual); Virtual += 1; } while (Virtual < End); KiIpiWaitForRequestBarrier(Barrier); } else { do { KiFlushSingleTb(*Virtual); Virtual += 1; } while (Virtual < End); } // // Lower IRQL to its previous value. // KeLowerIrql(OldIrql); return; }
VOID FASTCALL KeFlushSingleTb ( IN PVOID Virtual, IN BOOLEAN AllProcessors ) /*++ Routine Description: This function flushes a single entry from translation buffer (TB) on all processors that are currently running threads which are children of the current process. Arguments: Virtual - Supplies a virtual address that is within the page whose translation buffer entry is to be flushed. AllProcessors - Supplies a boolean value that determines which translation buffers are to be flushed. Return Value: The previous contents of the specified page table entry is returned as the function value. --*/ { PKAFFINITY Barrier; KIRQL OldIrql; PKPRCB Prcb; PKPROCESS Process; KAFFINITY TargetProcessors; // // Compute the target set of processors and send the flush single // parameters to the target processors, if any, for execution. // OldIrql = KeRaiseIrqlToSynchLevel(); Prcb = KeGetCurrentPrcb(); if (AllProcessors != FALSE) { TargetProcessors = KeActiveProcessors; } else { Process = Prcb->CurrentThread->ApcState.Process; TargetProcessors = Process->ActiveProcessors; } // // Send request to target processors, if any, flush the single entry from // the current TB, and wait for the IPI request barrier. // TargetProcessors &= ~Prcb->SetMember; if (TargetProcessors != 0) { Barrier = KiIpiSendRequest(TargetProcessors, (LONG64)Virtual, 0, IPI_FLUSH_SINGLE); KiFlushSingleTb(Virtual); KiIpiWaitForRequestBarrier(Barrier); } else { KiFlushSingleTb(Virtual); } // // Lower IRQL to its previous value. // KeLowerIrql(OldIrql); return; }
PVOID MmDbgTranslatePhysicalAddress ( IN PHYSICAL_ADDRESS PhysicalAddress ) /*++ Routine Description: MIPS implementation specific: This routine maps the specified physical address and returns the virtual address which maps the physical address. The next call to MmDbgTranslatePhyiscalAddress removes the previous phyiscal address translation, hence on a single physical address can be examined at a time (can't cross page boundaries). Arguments: PhysicalAddress - Supplies the phyiscal address to map and translate. Return Value: The virtual address which corresponds to the phyiscal address. NULL if the physical address was bogus. Environment: Kernel mode IRQL at DISPATCH_LEVEL or greater. --*/ { PVOID BaseAddress; PMMPTE BasePte; PMMPFN Pfn1; ULONG Page; BasePte = MmDebugPte + (MM_NUMBER_OF_COLORS - 1); BasePte = (PMMPTE)((ULONG)BasePte & ~(MM_COLOR_MASK << PTE_SHIFT)); Page = (ULONG)(PhysicalAddress.QuadPart >> PAGE_SHIFT); if ((Page > (LONGLONG)MmHighestPhysicalPage) || (Page < (LONGLONG)MmLowestPhysicalPage)) { return NULL; } Pfn1 = MI_PFN_ELEMENT (Page); if (!MmIsAddressValid (Pfn1)) { return NULL; } BasePte = BasePte + Pfn1->u3.e1.PageColor; BaseAddress = MiGetVirtualAddressMappedByPte (BasePte); KiFlushSingleTb (TRUE, BaseAddress); *BasePte = ValidKernelPte; BasePte->u.Hard.PageFrameNumber = Page; return (PVOID)((ULONG)BaseAddress + BYTE_OFFSET(PhysicalAddress.LowPart)); }