📄 hwsim.cpp
字号:
//
m_ImageSynth -> SetBuffer (NULL);
if (m_SynthesisBuffer) {
ExFreePool (m_SynthesisBuffer);
m_SynthesisBuffer = NULL;
}
//
// Delete the scatter / gather lookaside for this run.
//
ExDeleteNPagedLookasideList (&m_ScatterGatherLookaside);
return STATUS_SUCCESS;
}
/**************************************************************************
LOCKED CODE
**************************************************************************/
#ifdef ALLOC_PRAGMA
#pragma code_seg()
#endif // ALLOC_PRAGMA
ULONG
CHardwareSimulation::
ReadNumberOfMappingsCompleted (
)
/*++
Routine Description:
Read the number of scatter / gather mappings which have been
completed (TOTAL NUMBER) since the last reset of the simulated
hardware
Arguments:
None
Return Value:
Total number of completed mappings.
--*/
{
//
// Don't care if this is being updated this moment in the DPC... I only
// need a number to return which isn't too great (too small is ok).
// In real hardware, this wouldn't be done this way anyway.
//
return m_NumMappingsCompleted;
}
/*************************************************/
ULONG
CHardwareSimulation::
ProgramScatterGatherMappings (
IN PUCHAR *Buffer,
IN PKSMAPPING Mappings,
IN ULONG MappingsCount,
IN ULONG MappingStride
)
/*++
Routine Description:
Program the scatter gather mapping list. This shoves a bunch of
entries on a list for access during the fake interrupt. Note that
we have physical addresses here only for simulation. We really
access via the virtual address.... although we chunk it into multiple
buffers to more realistically simulate S/G
Arguments:
Buffer -
The virtual address of the buffer mapped by the mapping list
Mappings -
The KSMAPPINGS array corresponding to the buffer
MappingsCount -
The number of mappings in the mappings array
MappingStride -
The mapping stride used in initialization of AVStream DMA
Return Value:
Number of mappings actually inserted.
--*/
{
KIRQL Irql;
ULONG MappingsInserted = 0;
//
// Protect our S/G list with a spinlock.
//
KeAcquireSpinLock (&m_ListLock, &Irql);
//
// Loop through the scatter / gather list and break the buffer up into
// chunks equal to the scatter / gather mappings. Stuff the virtual
// addresses of these chunks on a list somewhere. We update the buffer
// pointer the caller passes as a more convenient way of doing this.
//
// If I could just remap physical in the list to virtual easily here,
// I wouldn't need to do it.
//
for (ULONG MappingNum = 0;
MappingNum < MappingsCount &&
m_ScatterGatherMappingsQueued < m_ScatterGatherMappingsMax;
MappingNum++) {
PSCATTER_GATHER_ENTRY Entry =
reinterpret_cast <PSCATTER_GATHER_ENTRY> (
ExAllocateFromNPagedLookasideList (
&m_ScatterGatherLookaside
)
);
if (!Entry) {
break;
}
Entry -> Virtual = *Buffer;
Entry -> ByteCount = Mappings -> ByteCount;
//
// Move forward a specific number of bytes in chunking this into
// mapping sized va buffers.
//
*Buffer += Entry -> ByteCount;
Mappings = reinterpret_cast <PKSMAPPING> (
(reinterpret_cast <PUCHAR> (Mappings) + MappingStride)
);
InsertTailList (&m_ScatterGatherMappings, &(Entry -> ListEntry));
MappingsInserted++;
m_ScatterGatherMappingsQueued++;
m_ScatterGatherBytesQueued += Entry -> ByteCount;
}
KeReleaseSpinLock (&m_ListLock, Irql);
return MappingsInserted;
}
/*************************************************/
NTSTATUS
CHardwareSimulation::
FillScatterGatherBuffers (
)
/*++
Routine Description:
The hardware has synthesized a buffer in scratch space and we're to
fill scatter / gather buffers.
Arguments:
None
Return Value:
Success / Failure
--*/
{
//
// We're using this list lock to protect our scatter / gather lists instead
// of some hardware mechanism / KeSynchronizeExecution / whatever.
//
KeAcquireSpinLockAtDpcLevel (&m_ListLock);
PUCHAR Buffer = reinterpret_cast <PUCHAR> (m_SynthesisBuffer);
ULONG BufferRemaining = m_ImageSize;
//
// For simplification, if there aren't enough scatter / gather buffers
// queued, we don't partially fill the ones that are available. We just
// skip the frame and consider it starvation.
//
// This could be enforced by only programming scatter / gather mappings
// for a buffer if all of them fit in the table also...
//
while (BufferRemaining &&
m_ScatterGatherMappingsQueued > 0 &&
m_ScatterGatherBytesQueued >= BufferRemaining) {
LIST_ENTRY *listEntry = RemoveHeadList (&m_ScatterGatherMappings);
m_ScatterGatherMappingsQueued--;
PSCATTER_GATHER_ENTRY SGEntry =
reinterpret_cast <PSCATTER_GATHER_ENTRY> (
CONTAINING_RECORD (
listEntry,
SCATTER_GATHER_ENTRY,
ListEntry
)
);
//
// Since we're software, we'll be accessing this by virtual address...
//
ULONG BytesToCopy =
(BufferRemaining < SGEntry -> ByteCount) ?
BufferRemaining :
SGEntry -> ByteCount;
RtlCopyMemory (
SGEntry -> Virtual,
Buffer,
BytesToCopy
);
BufferRemaining -= BytesToCopy;
Buffer += BytesToCopy;
m_NumMappingsCompleted++;
m_ScatterGatherBytesQueued -= SGEntry -> ByteCount;
//
// Release the scatter / gather entry back to our lookaside.
//
ExFreeToNPagedLookasideList (
&m_ScatterGatherLookaside,
reinterpret_cast <PVOID> (SGEntry)
);
}
KeReleaseSpinLockFromDpcLevel (&m_ListLock);
if (BufferRemaining) return STATUS_INSUFFICIENT_RESOURCES;
else return STATUS_SUCCESS;
}
/*************************************************/
void
CHardwareSimulation::
FakeHardware (
)
/*++
Routine Description:
Simulate an interrupt and what the hardware would have done in the
time since the previous interrupt.
Arguments:
None
Return Value:
None
--*/
{
m_InterruptTime++;
//
// The hardware can be in a pause state in which case, it issues interrupts
// but does not complete mappings. In this case, don't bother synthesizing
// a frame and doing the work of looking through the mappings table.
//
if (m_HardwareState == HardwareRunning) {
//
// Generate a "time stamp" just to overlay it onto the capture image.
// It makes it more exciting than bars that do nothing.
//
LONGLONG PtsRel = ((m_InterruptTime + 1) * m_TimePerFrame);
ULONG Min = (ULONG)(PtsRel / 600000000);
ULONG RemMin = (ULONG)(PtsRel % 600000000);
ULONG Sec = (ULONG)(RemMin / 10000000);
ULONG RemSec = (ULONG)(RemMin % 10000000);
ULONG Hund = (ULONG)(RemSec / 100000);
//
// Synthesize a buffer in scratch space.
//
m_ImageSynth -> SynthesizeBars ();
CHAR Text [256];
sprintf (Text, "%ld:%02ld.%02ld", Min, Sec, Hund);
//
// Overlay a clock onto the scratch space image.
//
m_ImageSynth -> OverlayText (
POSITION_CENTER,
(m_Height - 28),
1,
Text,
BLACK,
WHITE
);
//
// Overlay a counter of skipped frames onto the scratch image.
//
sprintf (Text, "Skipped: %ld", m_NumFramesSkipped);
m_ImageSynth -> OverlayText (
10,
10,
1,
Text,
TRANSPARENT,
BLUE
);
//
// Fill scatter gather buffers
//
if (!NT_SUCCESS (FillScatterGatherBuffers ())) {
InterlockedIncrement (PLONG (&m_NumFramesSkipped));
}
}
//
// Issue an interrupt to our hardware sink. This is a "fake" interrupt.
// It will occur at DISPATCH_LEVEL.
//
m_HardwareSink -> Interrupt ();
//
// Reschedule the timer if the hardware isn't being stopped.
//
if (!m_StopHardware) {
//
// Reschedule the timer for the next interrupt time.
//
LARGE_INTEGER NextTime;
NextTime.QuadPart = m_StartTime.QuadPart +
(m_TimePerFrame * (m_InterruptTime + 1));
KeSetTimer (&m_IsrTimer, NextTime, &m_IsrFakeDpc);
} else {
//
// If someone is waiting on the hardware to stop, raise the stop
// event and clear the flag.
//
m_StopHardware = FALSE;
KeSetEvent (&m_HardwareEvent, IO_NO_INCREMENT, FALSE);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -