Thought I would share my source code. This is one of the Synopsys DMA controllers (I do not have the specs for it). Instead I have the linux driver code so I am trying to make windows work from it. One of these days, I am going to boot Ubuntu 18.04, build the driver and see if it works. But the linux driver code was given to me so I am hoping it is the reference model.
The following is done during initialization. I have removed the code for error checking (The driver has it though).
WdfDeviceSetAlignmentRequirement(
device_ctxt,
FILE_BYTE_ALIGNMENT);
WDF_DMA_ENABLER_CONFIG_INIT(
&dmaConfig,
WdfDmaProfilePacket64, /* device is capable of addressing all 64-bits but no scatter gather */
8192);
status = WdfDmaEnablerCreate(
p_x1_device_ctxt->device,
&dmaConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&device_ctxt->DmaEnablerHandle
);
status = WdfCommonBufferCreate(
device_ctxt->DmaEnablerHandle,
p_x1_device_ctxt->common_dma_buffer_size, /* This is equal to 8192 */
WDF_NO_OBJECT_ATTRIBUTES,
&device_ctxt->h_common_dma_buffer
);
device_ctxt->common_dma_buffer_kernel_va =
WdfCommonBufferGetAlignedVirtualAddress(device_ctxt->h_common_dma_buffer);
device_ctxt->common_dma_buffer_device_la =
WdfCommonBufferGetAlignedLogicalAddress(device_ctxt->h_common_dma_buffer);
RtlZeroMemory(....)====> to zero out the common buffer
device_ctxt->common_buffer_mdl = IoAllocateMdl(device_ctxt->device_ctxt->common_dma_buffer_kernel_va , 8192, FALSE, FALSE, NULL)
Before the DMA starts, driver writes a pattern of 0xdeadbeef to the DMA buffer using another ioctl. I have verified this works.
When I get the ioctl to start the DMA (from device memory to system memory).
Driver logic to start DMA. The ioctl is a METHOD_BUFFERED and provides the size of dma and other parameters.
KeFlushIoBuffers(device_ctxt->common_buffer_mdl, TRUE, TRUE);
< I even threw in a __wbinvd() here to flush out the whole cache hierarchy. Did not make a difference >
regs->dest_addr_low = inputBuffer->internal_addr & 0xFFFFFFFF;
regs->dest_addr_high = inputBuffer->internal_addr >> 32;
regs->source_addr_low = device_ctxt->common_dma_buffer_device_la.LowPart;
regs->source_addr_high = device_ctxt->common_dma_buffer_device_la.HighPart;
regs->transfer_size = inputBuffer->num_dma_bytes;
< another write to another register in the DMA for some control operation>.
MemoryBarrier();
< write to the doorbell register to start the DMA>
After the above operation, I can see the dest_addr_low and source_addr_low being incremented by the num_dma_bytes.
The transfer_size register turns to zero.
But the data is not showing up in the common buffer DMA. I have a DbgPrintEx after the DMA for the first DWORD of the common buffer and it still shows 0xdeadbeef.