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.
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?
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…
//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…
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
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…
> 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…
“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
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).