Problem accessing Intel chipset configuration registers

I am writing a driver to access a specific read/write-once register in
the Intel ICH chipset configuration space.

My test is to set some write-once bits in the register, and then write
a clear to those same bits. This clear should silently fail and remain
at the first value written. (Verified in linux.)

The Intel spec states that the chipset configuration space mapped
location is set in the RCBA register. I can verify this also using
linux. So my physical memory location should be the address in the
RCBA plus any offset to the specific register I want. I looked in the
RCBA register to find the physical address of the chipset
configuration mapped memory block. Finding this, I then mapped it from
a physical into a virtual address using MmMapIoSpace() in the DDK.

Below is a snippet of my code, trying to run my tests and then convert
the location of that register into a unicode string to print to a
system log entry.

Am I doing something wrong here?

Thanks a bunch for the help,

Randy

– begin code snippet –

UNICODE_STRING uniErrorString ; // return string
VOID* virtAddr = NULL; // virtual address from MmMapIoSpace
ULONG memVal = 0; // value derived from memory mapped register
WCHAR addrBuffer[70]; // used to store the converted integer, or error
codes
PHYSICAL_ADDRESS memAddr2;
//ULONG addrSpace = 0x0; //memory, not IO space
ULONG oneBit = 0x010001; // for test write 1
ULONG zeroBit = 0x010000; // for test write 2

memAddr2.HighPart = 0x0;
// where xxx is replaced by the configuration register I am testing
memAddr2.LowPart = 0xFED1Cxxx; // address combined with offset as
indicated by RCBA

virtAddr = MmMapIoSpace(memAddr2,4,FALSE);

if ( virtAddr == NULL ) {
memVal = 0x00000002; // error condition
goto testDONE;
}

// should be able to set, and then the one should stay…clear bit
// should not replace it
// first test write
*(ULONG*)virtAddr = oneBit;

// test read
if ( *(ULONG*)virtAddr != oneBit ) {
RtlInitUnicodeString(&uniErrorString, L"0x0000000000000005");
// error condition
goto testDONE;
}

// test write, this should fail silently because of write-once bit
*(ULONGLONG*)virtAddr = zeroBit;
memVal = *(ULONGLONG*)virtAddr;

uniErrorString.Length = 0;
uniErrorString.MaximumLength = 70;
uniErrorString.Buffer = &addrBuffer[0];
// convert value to string
if ( STATUS_SUCCESS !=
RtlIntegerToUnicodeString(memVal,10,&uniErrorString) ) {
RtlInitUnicodeString(&uniErrorString, L"0x0000000000000003"); //
error
condition
}

testDONE:
// do error things…

Did you forget to tell us how it failed?

You are doing several things wrong.

  1. raw access to device memory is a bad idea, even if it works, even if it
    works on linux.
    On NT use the HAL READ/WRITE_REGISTER_* functions.

  2. if you insist on not using the hal then at least use volatile, as in
    volatile ULONG * foo;

  3. understand the bliss of the intel write post buffer. (see number one.)

  4. create a device driver for the chip and get your resources allocated to
    you the PnP way.
    If you are just fooling around, this is not necessary. If you are building a
    product you really should do things the right way.

Having said all that, none of the above may have anything to do with your
exact problem. I would use a debugger to step through your code. Windbg (and
I am sure softice) are able to access device memory.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Frenzy
Sent: Tuesday, September 21, 2004 5:35 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Problem accessing Intel chipset
configuration registers

I am writing a driver to access a specific read/write-once
register in the Intel ICH chipset configuration space.

My test is to set some write-once bits in the register, and
then write a clear to those same bits. This clear should
silently fail and remain at the first value written.
(Verified in linux.)

The Intel spec states that the chipset configuration space
mapped location is set in the RCBA register. I can verify
this also using linux. So my physical memory location should
be the address in the RCBA plus any offset to the specific
register I want. I looked in the RCBA register to find the
physical address of the chipset configuration mapped memory
block. Finding this, I then mapped it from a physical into a
virtual address using MmMapIoSpace() in the DDK.

Below is a snippet of my code, trying to run my tests and
then convert the location of that register into a unicode
string to print to a system log entry.

Am I doing something wrong here?

Thanks a bunch for the help,

Randy

– begin code snippet –

UNICODE_STRING uniErrorString ; // return string
VOID* virtAddr = NULL; // virtual address from MmMapIoSpace
ULONG memVal = 0; // value derived from memory mapped
register WCHAR addrBuffer[70]; // used to store the converted
integer, or error codes PHYSICAL_ADDRESS memAddr2; //ULONG
addrSpace = 0x0; //memory, not IO space ULONG oneBit =
0x010001; // for test write 1 ULONG zeroBit = 0x010000; //
for test write 2

memAddr2.HighPart = 0x0;
// where xxx is replaced by the configuration register I am
testing memAddr2.LowPart = 0xFED1Cxxx; // address combined
with offset as indicated by RCBA

virtAddr = MmMapIoSpace(memAddr2,4,FALSE);

if ( virtAddr == NULL ) {
memVal = 0x00000002; // error condition
goto testDONE;
}

// should be able to set, and then the one should
stay…clear bit // should not replace it // first test write
*(ULONG*)virtAddr = oneBit;

// test read
if ( *(ULONG*)virtAddr != oneBit ) {
RtlInitUnicodeString(&uniErrorString,
L"0x0000000000000005"); // error condition
goto testDONE;
}

// test write, this should fail silently because of
write-once bit *(ULONGLONG*)virtAddr = zeroBit;
memVal = *(ULONGLONG*)virtAddr;

uniErrorString.Length = 0;
uniErrorString.MaximumLength = 70;
uniErrorString.Buffer = &addrBuffer[0];
// convert value to string
if ( STATUS_SUCCESS !=
RtlIntegerToUnicodeString(memVal,10,&uniErrorString) ) {
RtlInitUnicodeString(&uniErrorString,
L"0x0000000000000003"); // error condition }

testDONE:
// do error things…


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as:
xxxxx@hollistech.com To unsubscribe send a blank email to
xxxxx@lists.osr.com

First thing I see is that you didn’t declare your memory pointer as
being volatile. I would suspect that your cycles are going where you
think they are going. I’d use the READ/WRITE_REGISTER_Xxx routines to do
your memory access.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Frenzy
Sent: Tuesday, September 21, 2004 2:35 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Problem accessing Intel chipset configuration registers

I am writing a driver to access a specific read/write-once register in
the Intel ICH chipset configuration space.

My test is to set some write-once bits in the register, and then write
a clear to those same bits. This clear should silently fail and remain
at the first value written. (Verified in linux.)

The Intel spec states that the chipset configuration space mapped
location is set in the RCBA register. I can verify this also using
linux. So my physical memory location should be the address in the
RCBA plus any offset to the specific register I want. I looked in the
RCBA register to find the physical address of the chipset
configuration mapped memory block. Finding this, I then mapped it from
a physical into a virtual address using MmMapIoSpace() in the DDK.

Below is a snippet of my code, trying to run my tests and then convert
the location of that register into a unicode string to print to a
system log entry.

Am I doing something wrong here?

Thanks a bunch for the help,

Randy

– begin code snippet –

UNICODE_STRING uniErrorString ; // return string
VOID* virtAddr = NULL; // virtual address from MmMapIoSpace
ULONG memVal = 0; // value derived from memory mapped register
WCHAR addrBuffer[70]; // used to store the converted integer, or error
codes
PHYSICAL_ADDRESS memAddr2;
//ULONG addrSpace = 0x0; //memory, not IO space
ULONG oneBit = 0x010001; // for test write 1
ULONG zeroBit = 0x010000; // for test write 2

memAddr2.HighPart = 0x0;
// where xxx is replaced by the configuration register I am testing
memAddr2.LowPart = 0xFED1Cxxx; // address combined with offset as
indicated by RCBA

virtAddr = MmMapIoSpace(memAddr2,4,FALSE);

if ( virtAddr == NULL ) {
memVal = 0x00000002; // error condition
goto testDONE;
}

// should be able to set, and then the one should stay…clear bit
// should not replace it
// first test write
*(ULONG*)virtAddr = oneBit;

// test read
if ( *(ULONG*)virtAddr != oneBit ) {
RtlInitUnicodeString(&uniErrorString, L"0x0000000000000005");
// error condition
goto testDONE;
}

// test write, this should fail silently because of write-once bit
*(ULONGLONG*)virtAddr = zeroBit;
memVal = *(ULONGLONG*)virtAddr;

uniErrorString.Length = 0;
uniErrorString.MaximumLength = 70;
uniErrorString.Buffer = &addrBuffer[0];
// convert value to string
if ( STATUS_SUCCESS !=
RtlIntegerToUnicodeString(memVal,10,&uniErrorString) ) {
RtlInitUnicodeString(&uniErrorString, L"0x0000000000000003"); //
error
condition
}

testDONE:
// do error things…


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: xxxxx@nvidia.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

I am new to the Windows kernel world, so its not surprising if I am
doing some things wrong. :slight_smile: The failure was determined by the fact
that I could write a 1 to a read-once bit…and then clear that 1
successfully. After changes the bit stays set after a clear.

After following one of your suggestions (see below) everything works
like a charm. Thanks to everyone who responded.

You are doing several things wrong.

  1. raw access to device memory is a bad idea, even if it works, even
    if it
    works on linux.
    On NT use the HAL READ/WRITE_REGISTER_* functions.

I gave these a try and bingo, it works! I had tried these before, but
that must have been before I had the physical address mapped to a
virtual. So the HAL layer must do some kind of translation of the
address to get the correct values from the register? I’ll do some
google’ing and see how this works.

Having said all that, none of the above may have anything to do with
your
exact problem. I would use a debugger to step through your code.
Windbg (and
I am sure softice) are able to access device memory.

Unfortunately the test board I am working on does not have serial
capability, so unless there is another method for kernel debugging
with windbg, I am out of luck. I have been debugging with error codes
sent to the system event log. Ugly and lots of reboots, but it works.

Thanks,

Randy