Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to translate a pci device physical address into CPU local address

680 views
Skip to first unread message

ling...@my-deja.com

unread,
Aug 5, 1999, 3:00:00 AM8/5/99
to
Hi,

I would like to know how to translate a pci device physical address
into CPU local address. The following is the specification

CPu Pentium board.
The Card is in Bus0, Slot 18 and Function 0
pci video card with the Physical memory range 0xfe000000 - 0xfeffffff

I would like to manuplate the video buffer. For this i need to
translate this address into CPU local address. Could anyone tell me how
to do this.

Thanks
s.shiva


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.

Scott Johnson

unread,
Aug 5, 1999, 3:00:00 AM8/5/99
to
ling...@my-deja.com wrote:

> Hi,
>
> I would like to know how to translate a pci device physical address
> into CPU local address. The following is the specification
>
> CPu Pentium board.
> The Card is in Bus0, Slot 18 and Function 0
> pci video card with the Physical memory range 0xfe000000 - 0xfeffffff
>
> I would like to manuplate the video buffer. For this i need to
> translate this address into CPU local address. Could anyone tell me how
> to do this.

PCI doesn't HAVE a static mapping of "PCI" memory to "local" memory.
It is the job of system software (either the OS or the system BIOS
on most systems, and NOT individual device drivers) to assing "resources"
to PCI devices and functions. "Resources", in this context, includes
memory regions, I/O space regions, and interrupts.

How it works is as follows (this describes the process on a PC). When a
PCI
comes up, the BIOS goes out and scans the PCI bus, noting all the devices
and bridges. It then goes and assigns the different types of resources to

the devices--memory such that all devices/functions on a given bus segment

occupy a roughly contiguous region of memory space (there may be small
gaps for
alignment); I/O is assigned in a similar fashion, and interrupts are
assigned based
on the function number of the device, and on whatever interrupt swizzling
occurs
on the bus. The algorithm to do this is pretty simple if you have only
one bus
segment; it gets more complicated with more than one.

In your case, you are using a Pentium. Is your platform essentially a
PC? If
so, you are lucky--your BIOS probably has done the hard work for you;
there
is a standard set of calls to the BIOS to do things like querying the
resources
assigned to devices, and converting to physical memory addresses.
Ideally, mapping of PCI addresses to local addresses requires no
translation;
rarely is it more difficult than adding a constant.

If you are using a custom Pentium designed, without a PC bios--you may be
out of luck. The PCI support in the vxWorks core is virtually
nonexistent;
some BSPs have PCI support (but usually a skeleton implementation, and
usually only for the host bridge on that board.) I have yet to see a
good, fully
compliant PCI implementation on vxWorks (except the one I wrote at
work :) That is for a Motorola MPC860 using a PLX9054 bridge, though--and

might not be very useful for a Pentium based design using whatever chipset

you are using. Plus my boss would probably kill me if I posted it to the
net... )


Hope that helps,

Scott

>
>
> Thanks
> s.shiva
>
> Sent via Deja.com http://www.deja.com/
> Share what you know. Learn what you don't.

--
------------------------------------------------------------------------
engineer_scotty (no, not that one) -- consumer of fine ales and lagers
some days you're the fire hydrant, some days you're the dog | go blazers
no small furry creatures were harmed in the creation of this .signature
------------------------------------------------------------------------


ling...@my-deja.com

unread,
Aug 6, 1999, 3:00:00 AM8/6/99
to
Thanks a lot Scott,

I would like to get some more clarification.
Yes i am using a Pentium Pc.

I scan the entire pci Bus to detect the cards.. like..
for (i=0;i< pci_max_bus;i++)
for(j=0;j<pci_max_device;j++)
for(k=0;k<pci_max_functions;k++)
pciConfigInLong(i,j,k,offset, &dwTemp)
if(dwTemp & 0xffffffff)
break;
else
store the device id, vendor id, Bus no, slot no,
function no in a structure .


One of the card detected was the cirrus video card with bus number 0,
slot number 18 and function number 0.

Then using the Bus no, slot no and function i read BAR 0 thru BAR 5.
Value at BAR 0 = 0xfe000000
value at Bar 1 = 0xfeffffff

The rest does not have any values.

After this i dont know how to access this address. i tried accessing
with out any translation. The program crashed.

> Ideally, mapping of PCI addresses to local addresses requires no
> translation;
> rarely is it more difficult than adding a constant.

I dont know how to get this constant, if any. Could you tell me how to
do this

regards,

Geurt

unread,
Aug 9, 1999, 3:00:00 AM8/9/99
to
The way of scanning the entire system seems OK.
It will get you all PCI devices alright.

And about VxWorks supporting PCI. It's ok. What is
needed is there. It is pretty much the specification of
the PCI BIOS (v2.1?) implemented. Additional functions
aren't available, but also not really needed. Although
some functions to simplify stuff, like what you are
doing, would be nice.

About the video card.
The base address you read from the configuration
registers is the base address of the linear frame
buffer of the video card.
I don't exactly know how you got it. I usually
just use pciConfigInLong with as offset
PCI_CFG_BASE_ADDRESS_x, defined in some
PCI header file.
If you want to use the address:

char *Ptr;

pciConfigInLong(
Bus,Dev,Func,PCI_CFG_BASE_ADDRESS_0,&dwTemp);

Ptr = (char *)dwTemp;

However, you can't just use this address, although doing so
should not make your application crash.

The linear frame buffer is only accessible when the video
card is in linear frame buffer mode (figures). At least nothing
can be done in text mode. In normal SVGA graphics mode,
maybe. It depends on what (Cirrus) card it is.

And last,
With PCI devices you usually want to know three things:
* The base address (In this case 0xfe000000)
* What is it (port or memory)
* What is the size
This can all be done, and if you like, I could post an code example.

Hope this helps,

-Geurt-

~warnings are just like errors, only not~

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Geurt Vos <G....@rohill.nl>
Junior Project Engineer
Rohill Engineering <http://www.rohill.nl>
Hoogeveen, The Netherlands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Extended Operating System Loader
http://come.to/geurt
ge...@geocities.com
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In article <7oe47j$oh4$1...@nnrp1.deja.com>,

ling...@my-deja.com

unread,
Aug 10, 1999, 3:00:00 AM8/10/99
to
Hi Geurt,
Thanks.

It would be really helpful for me if you can post some example code.

>I don't exactly know how you got it. I usually
>just use pciConfigInLong with as offset

>char *Ptr;
>pciConfigInLong(
> Bus,Dev,Func,PCI_CFG_BASE_ADDRESS_0,&dwTemp);
>Ptr = (char *)dwTemp;

Exactly this is the way i got the Base address.


>And last,
>With PCI devices you usually want to know three things:
>* The base address (In this case 0xfe000000)
>* What is it (port or memory)
>* What is the size

First, read the Bar0_Address and save for the later Usage

I am getting the above three as follows:

First, read the Bar0_Address and save for the later Usage

pciConfigInLong(busno,deviceno,function no, BAR0_ADDress, &dwSave)
To find whether it is IO mapped ot Memory Mapped
if(dwSave & 0x1)?IO_PORT:MEMORY_MAPPED

To find the range:
dwTemp = 0xfffffff0
first i write all 1's to BAR0. The last 4bits is not required to find
the range. So i write a 0 for the last 4 bits.
pciConfigOutLong(bus_no,Device_no,function_no, BAR0_ADDress, dwTemp)

Then i read the BAR0_Address
pciConfigOutLong(bus_no,Device_no,function_no, BAR0_ADDress, &dwTemp)

dwLoop = dwTemp >> 4
dwMemRange=0

for(i=0;i<28,i++)
{
if(dwLoop & 0x1)
break;
else
dwMemRange = dwMemRange << 1
dwLoop = dwLoop >> 1
}

So effectively, dwmemRange contans the Memory range the card can decode.

After this i set back the original address(dwSave) that the cards
BAR0_Address had.

Actually, i would like to know how to accesses the memory for any Pci
cards (memory Mapped) ( not necesserly Video card).

Specifically What i would like to know is
1) do i have to allocate a pool of memory and then write that address
into BAR0_Address as a base address

or as I have done in following code is sufficent ( i am not allocating
any memory pool)
dwmemAddress = Base address read from Bar0_Address
dwUserBuffer[20];
PDWORD *pdwTmp = (PDWORD*) dwUserBuffer;
idataBytes = 4;
while(idatabytes--) /* i am reading 16 bytes*/
*pdwTmp++ = *dwmemAddress++;

Thanks,
s.shiva


Hope this helps,

ling...@my-deja.com

unread,
Aug 10, 1999, 3:00:00 AM8/10/99
to
Hi Geurt,

I made a small typo error in the previous post. I am correcting that
mistake here.

> dwMemRange=0 /* I am correcting this line to
dwMemRange = 0x10;

Sorry about that
regards,
s.shiva

Geurt Vos

unread,
Aug 10, 1999, 3:00:00 AM8/10/99
to V x Works
>
>Hi Geurt,
>Thanks.
>
>It would be really helpful for me if you can post some example code.
>

Your example is how to do it (or better, how it can be done),
Although calculating the range is way easier. Consider the
following example:


unsigned long BaseAddr;
unsigned long MemSize;
int Type;
int Temp;

/* first read base address and memory type */
pciConfigInLong(
Bus,Dev,Func,PCI_CFG_BASE_ADDRESS_0,&Temp);
Type = (Temp & 0x01) ? IO_PORT : MEMORY_SPACE;
BaseAddr = Temp & 0xfffffff0;

/* calculate memory size */
pciConfigOutLong(
Bus,Dev,Func,PCI_CFG_BASE_ADDRESS_0,0xffffffff);
pciConfigInLong(
Bus,Dev,Func,PCI_CFG_BASE_ADDRESS_0,(int *)&MemSize);
if (Type == IO_PORT)
MemSize &= 0xfffffffc;
else
MemSize &= 0xfffffff0;
MemSize = ~MemSize + 1;

/* restore the original BAR value */
pciConfigOutLong(
Bus,Dev,Func,PCI_CFG_BASE_ADDRESS_0,Temp);


When the value of MemSize after the bitwise AND reads e.g.
0xffffff00. Inverted (bitwise NOT) it will be 0xff. Add one and
you have the memory size. You don't need to count zero-bits
to get the range.

Note that ~X + 1 == -X.

So instead of:
MemSize = ~MemSize + 1;
you could also do:
MemSize = -MemSize;

Though using the first one may seem somewhat clearer.

>Actually, i would like to know how to accesses the memory for any Pci
>cards (memory Mapped) ( not necesserly Video card).
>
>Specifically What i would like to know is
>1) do i have to allocate a pool of memory and then write that address
>into BAR0_Address as a base address
>

No, the value read from the BAR *is* the memory address you can use.
The memory you use is on the PCI board. It does not use the PC's
internal memory. Writing a new value to the BAR will just map the
memory on the PCI board to a new location.

>or as I have done in following code is sufficent ( i am not allocating
>any memory pool)
>dwmemAddress = Base address read from Bar0_Address
>dwUserBuffer[20];
>PDWORD *pdwTmp = (PDWORD*) dwUserBuffer;
>idataBytes = 4;
>while(idatabytes--) /* i am reading 16 bytes*/
>*pdwTmp++ = *dwmemAddress++;
>

This should be sufficient.

-Geurt-

~warnings are just like errors, only not~

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Geurt Vos <G....@rohill.nl>
Junior Project Engineer
Rohill Engineering <http://www.rohill.nl>
Hoogeveen, The Netherlands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Extended Operating System Loader
http://come.to/geurt
ge...@geocities.com
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Sent via Deja.com http://www.deja.com/

Ken Hayber

unread,
Aug 23, 1999, 3:00:00 AM8/23/99
to
You're probably getting a General Protection fault. It sounds like you need
to map the video linear address space so that it is read/write. This
requires modifying the GDT (global descriptor table) in SysLib.c I think.
The other way is to turn off ALL MMU support. This disables the x86 MMU
and allows access to any memory; unprotected. (In my project I turned off
MMU, it also hides a bug when lots of memory is installed >256MB; it gets
all fragmented.)

Also, just because the card tells you to use 0xe000000 doesn't mean its
ready to use that memory. Most SVGA cards need to be put in Linear Memory
mode first. Unless you really need linear SVGA, just use the VGA standard
memory space and ignore the PCI stuff.

Geurt <G....@rohill.nl> wrote in message news:7omh6b$a8c$1...@nnrp1.deja.com...


> The way of scanning the entire system seems OK.
> It will get you all PCI devices alright.
>
> And about VxWorks supporting PCI. It's ok. What is
> needed is there. It is pretty much the specification of
> the PCI BIOS (v2.1?) implemented. Additional functions
> aren't available, but also not really needed. Although
> some functions to simplify stuff, like what you are
> doing, would be nice.
>
> About the video card.
> The base address you read from the configuration
> registers is the base address of the linear frame
> buffer of the video card.

> I don't exactly know how you got it. I usually
> just use pciConfigInLong with as offset

> PCI_CFG_BASE_ADDRESS_x, defined in some
> PCI header file.
> If you want to use the address:
>

> char *Ptr;
>
> pciConfigInLong(
> Bus,Dev,Func,PCI_CFG_BASE_ADDRESS_0,&dwTemp);
>
> Ptr = (char *)dwTemp;
>

> However, you can't just use this address, although doing so
> should not make your application crash.
>
> The linear frame buffer is only accessible when the video
> card is in linear frame buffer mode (figures). At least nothing
> can be done in text mode. In normal SVGA graphics mode,
> maybe. It depends on what (Cirrus) card it is.
>

> And last,
> With PCI devices you usually want to know three things:
> * The base address (In this case 0xfe000000)
> * What is it (port or memory)
> * What is the size

> This can all be done, and if you like, I could post an code example.
>
> Hope this helps,
>

> -Geurt-
>
> ~warnings are just like errors, only not~
>
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> Geurt Vos <G....@rohill.nl>
> Junior Project Engineer
> Rohill Engineering <http://www.rohill.nl>
> Hoogeveen, The Netherlands
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> Extended Operating System Loader
> http://come.to/geurt
> ge...@geocities.com
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
>
>

0 new messages