Memory Resources

When I try to obtain I/O memory resources I get back good addresses but the lengths are zero. This card has two banks of memory. When I look at the card’s allocated resources via the device manager they show up as expected with addresses ranges that would indicate that a zero length should not be being returned. I doubt that it’s a device problem. The device works under Linux and a previous version worked under Windows as well. A code fragment follows. Any ideas on what might cause the zero length and/or how to handle it?

Wayne King

PIO_STACK_LOCATION stack;
PCM_PARTIAL_RESOURCE_LIST raw, translated;
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
PHYSICAL_ADDRESS membase;
ULONG memsize;

PAGED_CODE ();

pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

stack = IoGetCurrentIrpStackLocation (Irp);

raw = &stack->Parameters.StartDevice.
AllocatedResources->List[0].PartialResourceList;
translated = &stack->Parameters.StartDevice.
AllocatedResourcesTranslated->List[0].PartialResourceList;
resource = translated->PartialDescriptors;

for(Idx = 0; Idx < translated->Count; Idx++, resource++)
{
switch(resource->Type)
{
case CmResourceTypeMemory:
membase = resource->u.Memory.Start;
memsize = resource->u.Memory.Length;
KdPrint((LOGNAME “Mem Resource %8.8lX, len %8.8lX\n”, membase, memsize));
break;
}
}

xxxxx@orbitalnetwork.com wrote:

When I try to obtain I/O memory resources I get back good addresses but the lengths are zero. This card has two banks of memory. When I look at the card’s allocated resources via the device manager they show up as expected with addresses ranges that would indicate that a zero length should not be being returned. I doubt that it’s a device problem. The device works under Linux and a previous version worked under Windows as well. A code fragment follows. Any ideas on what might cause the zero length and/or how to handle it?

You are being fooled by printf. membase is a PHYSICAL_ADDRESS, which is
a 64-bit unsigned integer. You are printing it with %8.8lX, which
expects a 32-bit quantity. The reason you see 0 for memsize is that you
are actually seeing the upper 32-bits of membase. Thus, everything is
probably working just fine.

PIO_STACK_LOCATION stack;
PCM_PARTIAL_RESOURCE_LIST raw, translated;
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
PHYSICAL_ADDRESS membase;
ULONG memsize;

switch(resource->Type)
{
case CmResourceTypeMemory:
membase = resource->u.Memory.Start;
memsize = resource->u.Memory.Length;
KdPrint((LOGNAME “Mem Resource %8.8lX, len %8.8lX\n”, membase, memsize));
break;
}

You have two choices. The hacky solution is to cast membase to a
(ULONG) before printing. The proper solution is to tell KdPrint to
expect a 64-quantity by changing the format string to “Mem Resource
%8.8i64X, len %8.8lX\n”.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

The address (membase) comes out correctly. It’s the length (memsize) that always comes out zero. Or did I not understand something in your explanation.

Wayne

If I remember well PHYSICAL_ADDRESS is defined as a LARGE_INTEGER, so
printing it with %8.8IX will not work. You need to use %8.8I64X.

Have a nice day
GV

----- Original Message -----
From:
To: “Windows System Software Devs Interest List”
Sent: Monday, July 02, 2007 8:22 AM
Subject: [ntdev] Memory Resources

> When I try to obtain I/O memory resources I get back good addresses but
> the lengths are zero. This card has two banks of memory. When I look at
> the card’s allocated resources via the device manager they show up as
> expected with addresses ranges that would indicate that a zero length
> should not be being returned. I doubt that it’s a device problem. The
> device works under Linux and a previous version worked under Windows as
> well. A code fragment follows. Any ideas on what might cause the zero
> length and/or how to handle it?
>
> Wayne King
>
> PIO_STACK_LOCATION stack;
> PCM_PARTIAL_RESOURCE_LIST raw, translated;
> PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
> PHYSICAL_ADDRESS membase;
> ULONG memsize;
>
> PAGED_CODE ();
>
> pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
>
> stack = IoGetCurrentIrpStackLocation (Irp);
>
> raw = &stack->Parameters.StartDevice.
> AllocatedResources->List[0].PartialResourceList;
> translated = &stack->Parameters.StartDevice.
> AllocatedResourcesTranslated->List[0].PartialResourceList;
> resource = translated->PartialDescriptors;
>
> for(Idx = 0; Idx < translated->Count; Idx++, resource++)
> {
> switch(resource->Type)
> {
> case CmResourceTypeMemory:
> membase = resource->u.Memory.Start;
> memsize = resource->u.Memory.Length;
> KdPrint((LOGNAME “Mem Resource %8.8lX, len %8.8lX\n”, membase, memsize));
> break;
> }
> }
>
>
> —
> Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer

This is because the first “%8.8IX” prints the lower 32 bits of the address.

When you write
printf(“%8.8IX %8.8IX”, membase, memsize);

you will actually print (on a little endian machine) the low 32 bits of
membase followed by the high 32 bits of membase. memsize is not printed at
all by that code.

Please try this “%8.8I64X %8.8IX” and you’ll see the right data printed in
the log.

Hope it helps
GV

----- Original Message -----
From:
To: “Windows System Software Devs Interest List”
Sent: Monday, July 02, 2007 10:45 AM
Subject: RE:[ntdev] Memory Resources

> The address (membase) comes out correctly. It’s the length (memsize) that
> always comes out zero. Or did I not understand something in your
> explanation.
>
> Wayne
>
> —
> Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer

xxxxx@orbitalnetwork.com wrote:

The address (membase) comes out correctly. It’s the length (memsize) that always comes out zero. Or did I not understand something in your explanation.

Yes, you did not understand my explanation. membase only comes out
correctly because you happen to get physical addresses that fit in 32 bits.

Let’s say that membase is 0x0000000012340000, and memlen is 0x56780000.
By the time we get into KdPrint, the stack looks like this:

esp -> return address
esp+ 4 -> address of format string
esp+ 8 -> 12340000 membase low half
esp+12 -> 00000000 membase high half
esp+16 -> 56780000 memsize

So, now printf starts looking for parameters. It sees %8.8lX and says
“I need a 32-bit parameter”. It pulls off the “12340000” and prints
that. Now it sees another %8.8lX and says “I need another 32-bit
parameter”. It pulls off the “00000000” and prints that. That
“00000000” happens to be the high-order 32-bits of “membase”, but printf
can’t know that, because you told it you needed two 32-bit parameters.

At that point, it’s done, and it will return with the 56780000 untouched.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Hmm, interesting problem. Using %8.8I64X yields the same result. It still doesn’t make sense to me. I understand how the address would be incorrect but memsize is a different parameter so the formatting of it should be independent of what came before it. Why would the processing of the second parameter assume it was contiguous with the first one on the stack? Bottom line though is that it is a printf formatting problem. The correct value is really there. Thanks all.

Wayne

> At that point, it’s done, and it will return with the 56780000 untouched.

Doubts.

printf() and similar (in fact, any function with ellipsis in the arg list) are
__cdecl.

__cdecl functions require the caller to unload the args from stack. So, they
end with usual RET opcode, and the caller does something like:

call _printf
add esp, 12

So, providing wrong format spec/number of args to printf() and similar will not
cause a stack corruption crash.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

What does !cmreslist

say? It will give
you the proper length

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@orbitalnetwork.com
Sent: Monday, July 02, 2007 1:34 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Memory Resources

Hmm, interesting problem. Using %8.8I64X yields the same result. It
still doesn't make sense to me. I understand how the address would be
incorrect but memsize is a different parameter so the formatting of it
should be independent of what came before it. Why would the processing
of the second parameter assume it was contiguous with the first one on
the stack? Bottom line though is that it is a printf formatting
problem. The correct value is really there. Thanks all.

Wayne

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

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

----- Original Message -----
From:
To: “Windows System Software Devs Interest List”
Sent: Monday, July 02, 2007 1:33 PM
Subject: RE:[ntdev] Memory Resources

> Hmm, interesting problem. Using %8.8I64X yields the same result. It
> still doesn’t make sense to me. I understand how the address would be
> incorrect but memsize is a different parameter so the formatting of it
> should be independent of what came before it. Why would the processing of
> the second parameter assume it was contiguous with the first one on the
> stack? Bottom line though is that it is a printf formatting problem. The
> correct value is really there. Thanks all.
>

Parameters are put on the stack in a sequential order. And printf has no
idea what is on the stack. So it pops out values following the directions in
the printf formatting string. If the string is wrong (like %8.8IX), the
second %8.8IX will pop a 32bit word from the stack that actually relates to
the 64bit address.

From your mail it looks like you solved your problem (i.e. memsize is
actually != 0), but the printf still doesnt work. Right? The right one is
“%16.16I64X %8.8IX” (you can also use %8.8I64X).

GV

> Wayne
>
> —
> Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer

Maxim S. Shatskih wrote:

> At that point, it’s done, and it will return with the 56780000 untouched.
>

Doubts.

printf() and similar (in fact, any function with ellipsis in the arg list) are
__cdecl.

__cdecl functions require the caller to unload the args from stack. So, they
end with usual RET opcode, and the caller does something like:

call _printf
add esp, 12

So, providing wrong format spec/number of args to printf() and similar will not
cause a stack corruption crash.

By “untouched” I meant “not used in the printf operation”. Because
printf is cdecl, it is not a problem if the caller supplies more
parameters than the format string needs.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

xxxxx@orbitalnetwork.com wrote:

Hmm, interesting problem. Using %8.8I64X yields the same result.

That’s odd, because it should have worked. I’ve done that same
operation many times.

It still doesn’t make sense to me. I understand how the address would be incorrect but memsize is a different parameter so the formatting of it should be independent of what came before it. Why would the processing of the second parameter assume it was contiguous with the first one on the stack?

This is just the way that functions with variable argument lists (called
“variadic” functions) work in C. The function being called has
literally no idea what parameters you actually sent, how many there
were, or what size they were. It receives a pile of bytes on the stack,
and it has to make sense out of them. Somehow, the non-variable
parameters have to tell the function what parameters it really got.

For the Microsoft C compiler, parameters that are 32-bits or less are
always passed on the stack as a 32-bit unit. So, if you push an
unsigned char, it still gets pushed as a dword. Thus, if you do this:
printf( “%c %x\n”, 0x61616161, ‘c’ );
it all works fine. Both parameters gets sent as dword, and printf
expects to get two dwords. The first one will get truncated for
printing, but that’s OK.

However, 64-bit values are passed on the stack as 64-bit values – two
dwords. Printf has no way of knowing that. There are no indications on
the stack that tell it where one parameter begins and another one ends.
It’s just a pile of bytes. So, when you pass a 64-bit value, you have
to tell printf that the next item on the stack is a 64-bit value, using
the “I64” modifier.

Printf believed you, and you were lying to it. GIGO, just that easy.

Bottom line though is that it is a printf formatting problem. The correct value is really there.

It’s always good when a sad story has a happy ending…


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.