WDF: CmResourceTypeMemoryLarge BAR

Hello,

In case the **type ** field in CM_PARTIAL_RESOURCE_DESCRIPTOR is : CmResourceTypeMemoryLarge
The **Flags ** field determines if to use Memory40, Memory48 or Memory64

In case I should use Memory64, what is the size of the BAR: Length64 * ?

Thank you,
Zvika

I don’t understand the question.

If you’re asking whether the BAR itself is 32 or 64 bits, this is determined by bits 1 and 2 of the BAR. But that’s not relevant, really, because Windows handles that for you… you get the address and length in the memory resource.

Peter

Hi Peter,

According to the device manager I have:
Large memory range 6000000000 - 63FFFFFFFF

In the init of the kernel module code I scan the resources:

PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;

for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++)
{
desc = WdfCmResourceListGetDescriptor(ResourcesTranslated, i);
//desc->Type = 7
//desc->u.Memory.Length = 0x4000000;
}

So I suspected the length I got is not in bytes.
Is it possible ?
Should I map this BAR with MmMapIoSpace as I do with “regular” BARs that
have type 3 ?

Thank you,
Zvika

Hello,

desc->Flags = 0x284 which means:
CM_RESOURCE_MEMORY_LARGE_40 | CM_RESOURCE_MEMORY_BAR | CM_RESOURCE_MEMORY_PREFETCHABLE

After firmware change, desc->u.Memory.Length = 0x1000000
But according to device manager, the size is 4GB (not just 16MB as reported by driver)

The goal is to map a 4GB DDR connected to the FPGA. It’s not the DDR of the PC.

Thank you,
Zvika

You have to shift the length by some amount when one of the length flags is set… that’s the purpose of the flag. For _40 I think you shift left 8 bits? It’s in the docs…

Peter

Hi Peter,

For this 4GB BAR I called:
PVOID *p =MmMapIoSpace (0x100000000, MmNonCached); //0x1000000 * 256
But got: p=null

Thank you,
Zvika

Hmmm… MmMapIoSpace takes three arguments, not two.

Note you can use RtlCmDecodeMemIoResource to properly decode/determine the base address and length (I admit it, I didn’t know about this function until I Googled around a bit this morning… I had always done the work manually with the shifting that’s documented in the WDK).

I’m guessing it just returns the address that’s given as the Start address in the Memory resource?

Peter

After firmware change, desc->u.Memory.Length = 0x1000000

As the doc says, if CM_RESOURCE_MEMORY_LARGE_40 is set, you should be using desc-> u.Memory40.Length40 << 8. Yes, it’s the same memory location, but the name reminds you why you are shifting by 8.

Hi Tim, Peter,

Is it possible to know why:
MmMapIoSpace (0, 0x100000000, MmNonCached);
returns 0x0 ?

Thank you,
Zvika

Because 0x0000 isn’t a valid base address, maybe?

You know the next question, right: “What is it that you’re trying to accomplish”?

Peter

Have you looked at the documentation to understand what that is asking for? You’re trying to create a virtual mapping for the low-order 4 gigabytes of physical space. Most of that space is physical RAM, although the top gigabyte holds PCI devices. The bigger problem is that you are asking for MmNonCached. If you are mapping physical space that has already been mapped, then your caching attribute must match the existing mapping. Physical memory and most PCI devices are mapped as cached.

Hi Tim, Peter,

I have 4GB DDR connected directly to the FPGA. It is not part of the PC’s DDR
The goal is to map this 4GB DDR so I can access it via PCIe (PC ↔ FPGA ↔ DDR).
Can you please tell what is the right way to do it ?

During application init, the PC writes data to this 4GB DDR.
Upon init completion, FPGA reads from this DDR.

Thank you,
Zvika

You map it in your driver the way you map any memory resource… as part of your PrepareHardware callback. Haven’t we been talking about this for the past several days already? Peter

Hi Peter,

This is exactly what I’m doing:

PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
PHYSICAL_ADDRESS Bar0Address ;
ULONG Bar0Length ;
PVOID Bar0VirtualAddress ;
ULONG i; i;

for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {

         desc = WdfCmResourceListGetDescriptor(ResourcesTranslated, i);

        if (desc->Type ==CmResourceTypeMemoryLarge)
        {
                  Bar0Address = desc->u.Memory40.Start;
                  Bar0Length = desc->u.Memory40.Length40 << 8;
        }

}

Bar0VirtualAddress = MmMapIoSpace (Bar0Address , 0x100000000, MmNonCached) ;

But the value of Bar0VirtualAddress is 0x0.
It means that mapping failed.
Currently, the FPGA design contains only one BAR.

Thank you,
Zvika

That’s definitely clearer. Thank you.

So… the value in BAR0 is zero? Ignoring what you’re getting in the Resource from Windows… you look at the BAR and the base address is zero?

That means either (a) your device isn’t provisioning this BAR properly, (b) the BIOS can’t find a [perhaps large-enough] slot for it, (c) the BIOS doesn’t support memory resources as large as the one your device is requesting.

The problem here isn’t your call to MmMapIoSpace… the problem is that you’re getting a base physical address of zero for your BAR. As you’ve discovered zero is not a valid base address for your memory segment. Anytime I’ve seen this, it’s always been an error in the FPGA (code) setup.

Peter

ULONG Bar0Length ;

Bar0Length = desc->u.Memory40.Length40 << 8;

Your length is larger than a ULONG, so Bar0Length will end up as 0. Didn’t you get compiler warnings on that line? Are you ignoring compiler warnings? You definitely should not do that.

Hi Tim,

You are right !
When I modifled to:
ULONG64 Bar0Length;

It worked.
At least in my IDE (V.S 2015) there were no warnings when I used ULONG.

I really appreciate your help !
Best regards,
Zvika

Chalk up another “win” for Mr. @Tim_Roberts, who actually reads the code that people post, and carefully.

Bravo, and thanks, Mr. Roberts!

Peter