An issue about NdisMMapIoSpace API

Hi, Everyone,

I’m writing a NIDS driver for e1000 NIC. I have met one problem as following:

I called the function NdisMMapIoSpace to get the virtual address of the NIC registers. When I get the address, I’m trying to read the data of these registers via this virtual address. But I find the data that I read does not match what the data of the registers is supposed to be, according the e1000 NIC spec.

My code is as following:

/****************************************************************/

PVOID *VirtualAddress;

status = NdisMMapIoSpace(VirtualAddress, MiniportAdapterHandle, PhysicalAddress, Lenght);

p_cal = (PULONG)(*VirtualAddress);

//
//0x00008 and 0x000C0 is the offset of the register according to the spec
//

DbgPrint(“The first register is %X\n”, i, *p_cal));
DbgPrint(“The second register is %X\n”, i, *(p_cal+0x00008));
DbgPrint(“The ICR register is %X\n”, i, *(p_cal+0x000C0));

/****************************************************************/

So I’m not sure if I am reading the data in correct way? Could someone share me how to correspond the memory from MMIO to the registers of the hardware device?

Thanks so much.

-Arike

Have you checked the return status?

Mm
On Jul 16, 2011 7:22 PM, wrote:
> Hi, Everyone,
>
> I’m writing a NIDS driver for e1000 NIC. I have met one problem as
following:
>
> I called the function NdisMMapIoSpace to get the virtual address of the
NIC registers. When I get the address, I’m trying to read the data of these
registers via this virtual address. But I find the data that I read does not
match what the data of the registers is supposed to be, according the e1000
NIC spec.
>
> My code is as following:
>
> /*****/
>
> PVOID VirtualAddress;
>
> status = NdisMMapIoSpace(VirtualAddress, MiniportAdapterHandle,
PhysicalAddress, Lenght);
>
> p_cal = (PULONG)(VirtualAddress);
>
> //
> //0x00008 and 0x000C0 is the offset of the register according to the spec
> //
>
> DbgPrint(“The first register is %X\n”, i, p_cal));
> DbgPrint(“The second register is %X\n”, i, (p_cal+0x00008));
> DbgPrint(“The ICR register is %X\n”, i, (p_cal+0x000C0));
>
> /
/
>
> So I’m not sure if I am reading the data in correct way? Could someone
share me how to correspond the memory from MMIO to the registers of the
hardware device?
>
> Thanks so much.
>
> -Arike
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Yes, the status is 0, I think NdisMMapIoSpace works, otherwise, I will get the NULL pointer for the virtual address. It seems that I’m not in the correct way to read the data…

Have you checked the return status?

Mm

> p_cal = (PULONG)(*VirtualAddress);

p_cal is a pointer to ULONG, right…

//0x00008 and 0x000C0 is the offset of the register according to the spec

These offsets are expressed in bytes, right. Therefore, if you think of p_cal as of an array of 4-byte ULONGs, your target registers are respectively p_cal[2] and p_cal[3]…

DbgPrint(“The first register is %X\n”, i, *p_cal));
> DbgPrint(“The second register is %X\n”, i, *(p_cal+0x00008));
> DbgPrint(“The ICR register is %X\n”, i, *(p_cal+0x000C0))

…but you print out p_cal[8] and p_cal[0xC] instead. Don’t forget that array and pointer are the same thing in C, so that *(ptr+N) is exactly the same thing as ptr[N]

Therefore, there is nothing more than a mistake with pointer arithmetic…

Anton Bassov

Hi, Anton,

You are right,

I got it work when I switch to use *(p_cal + offset/4).

I would though the offset should be the count number of the registers instead of bytes in memory, and each register has 4bytes length, so I directly use ULONG array. It is totally wrong.

Thanks so much :slight_smile:

Best,

Li


p_cal = (PULONG)(*VirtualAddress);

p_cal is a pointer to ULONG, right…

//0x00008 and 0x000C0 is the offset of the register according to the spec

These offsets are expressed in bytes, right. Therefore, if you think of p_cal as
of an array of 4-byte ULONGs, your target registers are respectively p_cal[2]
and p_cal[3]…

DbgPrint(“The first register is %X\n”, i, *p_cal));
> DbgPrint(“The second register is %X\n”, i, *(p_cal+0x00008));
> DbgPrint(“The ICR register is %X\n”, i, *(p_cal+0x000C0))

…but you print out p_cal[8] and p_cal[0xC] instead. Don’t forget that array
and pointer are the same thing in C, so that *(ptr+N) is exactly the same thing
as ptr[N]

Therefore, there is nothing more than a mistake with pointer arithmetic…

Anton Bassov

> I would though the offset should be the count number of the registers instead of bytes in memory,

and each register has 4bytes length

Well, this is not how they do it in specifications, although it is perfectly reasonable from the programmer’s perspective. Just define REG_ABC as 1, REG_XYZ as 2, etc so that you will be able to use
these definitions as indexes into your array…

so I directly use ULONG array.

Don’t forget that ‘unsigned long’ data type is machine-specific, i.e. it can be either 4 or 8 bytes. Therefore, on 64-bit system you will get the results different from the ones you get on 32-bit one. Use DWORD instead - IIRC, it is typedef for ‘unsigned int’ so that it is guaranteed to be 4 bytes wide everywhere…

Anton Bassov

“Unsigned long” is 32 bit on both 32 bit and 64 bit windows.

Mm
On Jul 16, 2011 10:36 PM, wrote:
>
>> I would though the offset should be the count number of the registers
instead of bytes in memory,
>> and each register has 4bytes length
>
> Well, this is not how they do it in specifications, although it is
perfectly reasonable from the programmer’s perspective. Just define REG_ABC
as 1, REG_XYZ as 2, etc so that you will be able to use
> these definitions as indexes into your array…
>
>
>> so I directly use ULONG array.
>
> Don’t forget that ‘unsigned long’ data type is machine-specific, i.e. it
can be either 4 or 8 bytes. Therefore, on 64-bit system you will get the
results different from the ones you get on 32-bit one. Use DWORD instead -
IIRC, it is typedef for ‘unsigned int’ so that it is guaranteed to be 4
bytes wide everywhere…
>
>
> Anton Bassov
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

xxxxx@hotmail.com wrote:

> so I directly use ULONG array.

Don’t forget that ‘unsigned long’ data type is machine-specific, i.e. it can be either 4 or 8 bytes. Therefore, on 64-bit system you will get the results different from the ones you get on 32-bit one. Use DWORD instead - IIRC, it is typedef for ‘unsigned int’ so that it is guaranteed to be 4 bytes wide everywhere…

Or even better UINT32 since it is more explicit and obvious (at least to
those of us who weren’t weaned on Microsoft’s strange type names).

> “Unsigned long” is 32 bit on both 32 bit and 64 bit windows.

Duh. Played with Linux too much…

–pa

Why is there " i," in those DbgPrint calls?

ooops…, that’s a debug information that I forgot to get rid of.

Never mind :slight_smile:

Why is there " i," in those DbgPrint calls?