Page 1 of 4
accessing the network card
Posted: Fri May 07, 2010 11:09 pm
by aloktiagi
HI
How can we find the network card on the PCI bus and access its memory addresses and registers. Main idea is to initialize the NIC, access its address space.
Can someone provide any links for this information
BR
Alok
Re: accessing the network card
Posted: Sat May 08, 2010 2:30 am
by Combuster
You may want to look up your keywords in the wiki before posting them here:
PCI
Re: accessing the network card
Posted: Sat May 08, 2010 7:43 am
by aloktiagi
Hi,
Yes had gone through that before posting!!. My code for now has a bootloader that jumps to c code which has set gdt and idt. Now i want to access pci deivces i.e NIC.
So needed some guidance on that!!
BR
Alok
Re: accessing the network card
Posted: Sat May 08, 2010 8:06 am
by Creature
The article Combuster linked to describes how to access PCI devices; it is now up to you to find the device you need in PCI configuration space and to program it (which is usually somewhat dependant on the device itself). If it's a specific network card you're looking for, you might have some luck
browsing through the category.
Re: accessing the network card
Posted: Sat May 08, 2010 10:51 pm
by ehenkes
You should implement functions to scan the pci bus and to read/write to pci registers. Then you will have something like:
Code: Select all
void pciScan()
{
for (uint32_t i=0;i<PCIARRAYSIZE;++i)
{
pciDev_Array[i].number = i;
}
int number=0;
for (uint8_t bus = 0; bus < 4; ++bus) // we scan only four busses of 256 possibles
{
for (uint8_t device = 0; device < 32; ++device)
{
for (uint8_t func = 0; func < 8; ++func)
{
uint16_t vendorID = pci_config_read(bus, device, func, PCI_VENDOR_ID);
if (vendorID && (vendorID != 0xFFFF))
{
//...
/// RTL 8139 network card
if ((pciDev_Array[number].deviceID == 0x8139))
{
install_RTL8139(number);
}
++number;
The wiki is very helpful regarding PCI bus.
The install routine for the speciifc network card could be like this:
Code: Select all
void install_RTL8139(uint32_t number)
{
for (uint8_t j=0;j<6;++j) // check network card BARs
{
pciDev_Array[number].bar[j].memoryType = pciDev_Array[number].bar[j].baseAddress & 0x01;
if (pciDev_Array[number].bar[j].baseAddress) // check valid BAR
{
if (pciDev_Array[number].bar[j].memoryType == 0)
{
BaseAddressRTL8139_MMIO = pciDev_Array[number].bar[j].baseAddress &= 0xFFFFFFF0;
}
if (pciDev_Array[number].bar[j].memoryType == 1)
{
BaseAddressRTL8139_IO = pciDev_Array[number].bar[j].baseAddress &= 0xFFFC;
}
}
}
Good luck!
Re: accessing the network card
Posted: Sun May 09, 2010 12:58 am
by aloktiagi
Hi
Thanks for the reply
To do this i'll need to implement
pci_config_read function also.
One more thing i was following the wiki page
http://wiki.osdev.org/RTL8169. Here it tells how to get the MAC address of the card. Is this tutorial correct?
Now to get the I/O base address from PCI configuration space i used lspci command and ifconfig and i got the following
lspci
05:00.0 Ethernet controller: Broadcom Corporation NetXtreme II BCM5708 Gigabit Ethernet (rev 12)
Subsystem: Hewlett-Packard Company NC373i Integrated Multifunction Gigabit Server Adapter
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr+ Stepping- SERR+ FastB2B-
Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Latency: 64 (16000ns min), Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 130
Region 0: Memory at fa000000 (64-bit, non-prefetchable) [size=32M]
[virtual] Expansion ROM at d1200000 [disabled] [size=2K]
Capabilities: [40] PCI-X non-bridge device
Command: DPERE- ERO- RBC=512 OST=8
Status: Dev=05:00.0 64bit+ 133MHz+ SCD- USC- DC=simple DMMRBC=512 DMOST=8 DMCRS=32 RSCEM- 266MHz- 533MHz-
Capabilities: [48] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold+)
Status: D0 PME-Enable- DSel=0 DScale=1 PME-
Capabilities: [50] Vital Product Data
Capabilities: [58] Message Signalled Interrupts: 64bit+ Queue=0/0 Enable+
Address: 00000000fee01000 Data: 4082
and ifconfig i get
eth1 Link encap:Ethernet HWaddr 00:1F:29:CC:BC:12
inet addr:10.58.112.248 Bcast:10.58.112.255 Mask:255.255.255.0
inet6 addr: fe80::21f
fecc:bc12/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:103895656 errors:1 dropped:0 overruns:0 frame:1
TX packets:73155493 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:702144647 (669.6 MiB) TX bytes:561130821 (535.1 MiB)
Interrupt:82 Memory:fa000000-fa012100
So is the I/O base address fa000000???
Thanks
Alok
Re: accessing the network card
Posted: Sun May 09, 2010 12:44 pm
by Selenic
aloktiagi wrote:So is the I/O base address fa000000???
Kind of. The lspci output (in particular) states that it owns a chunk of *memory* at that location. Not IO address space, which in many cases is only used for legacy compatibility; most stuff uses memory mapping like that.
That chunk of memory will, however, have the various controls registers, buffers and whatever else laid out within it (though you'll likely need to find documentation for that specific card or series of cards)
Re: accessing the network card
Posted: Mon May 10, 2010 1:05 am
by aloktiagi
Hi,
So how do i find out the I/O base address of a device when i jump from my bootloader to the c code without the OS being there i.e no lspci command!!!
Regards
Alok
Re: accessing the network card
Posted: Mon May 10, 2010 2:26 am
by Combuster
So how do i find out the I/O base address of a device when i jump from my bootloader to the c code without the OS being there i.e no lspci command!!!
Please, if you ask an answered question again in the same thread it only makes you look like you are lazy and want to be spoon-fed code. Please
read the links posted earlier in this thread before trying again. If you do actually get stuck, at least make some effort showing us what you did so far.
(see here why)
I wrote:You may want to look up your keywords in the wiki before posting them here:
PCI
Re: accessing the network card
Posted: Mon May 10, 2010 10:08 am
by aloktiagi
Hi,
In code at the PCI Wiki link
Code: Select all
unsigned short pciConfigReadWord (unsigned short bus, unsigned short slot,
unsigned short func, unsigned short offset)
{
unsigned long address;
unsigned long lbus = (unsigned long)bus;
unsigned long lslot = (unsigned long)slot;
unsigned long lfunc = (unsigned long)func;
unsigned short tmp = 0;
/* create configuration address as per Figure 1 */
address = (unsigned long)((lbus << 16) | (lslot << 11) |
(lfunc << 8) | (offset & 0xfc) | ((UINT32)0x80000000));
/* write out the address */
sysOutLong (0xCF8, address);
/* read in the data */
tmp = (unsigned short)((sysInLong (0xCFC) >> ((offset & 2) * 8)) & 0xffff);
return (tmp);
}
What is meant by the offset??
Alok
Re: accessing the network card
Posted: Mon May 10, 2010 10:22 am
by Combuster
What do (should) you do when you don't know what a word means: you derive it from the context. The same holds for code:
Enable Bit - Reserved - Bus Number - Device Number - Function Number - Register Number - 00
(...)
/* create configuration address as per Figure 1 */
address = (unsigned long)((lbus << 16) | (lslot << 11) | (lfunc << 8 ) | (offset & 0xfc) | ((UINT32)0x80000000));
Draw the lines and entertain me
Re: accessing the network card
Posted: Tue May 11, 2010 9:49 am
by aloktiagi
Hi,
Currently my code goes like this (my broadcom BCM5708 card's parameters are bus 3 and device 0)
Code: Select all
for(i=0;i<10;i++)
{
idx = 0x80000000 + ((0x03&0xFF)<<16) + ((0x00&0x1F)<<11) + ((0x00&0x7)<<8) + (header&0xFC);
outl(idx,0xCF8);
tmp = inl(0xCFC);
if ( tmp == ~0 ) printf("alok");
printf( " ADDR=%X REG VAL=%X \n",header, tmp);
header=header+0x04;
}
The output i get is
ADDR=0 REG VAL=164C14E4 Device and vendor ID
ADDR=4 REG VAL=2B00156
ADDR=8 REG VAL=2000011
ADDR=C REG VAL=4010
ADDR=10 REG VAL=F8000004
ADDR=14 REG VAL=0
ADDR=18 REG VAL=0
ADDR=1C REG VAL=0
ADDR=20 REG VAL=0
ADDR=24 REG VAL=0
So 0xF800004 is my BAR0 value.
Now the
http://wiki.osdev.org/PCI link tells that to retrieve the actual base address of a BAR
we need to mask the lower bits, i.e BAR[x] & 0xFFFFFFF0 for 32 bit. So after this i get the BAR address as 0xF800000.
So from 0xF800000 can i now access the NIC's registers, for e.g get the MAC address values?
Regards
Alok
Re: accessing the network card
Posted: Tue May 11, 2010 10:50 pm
by aloktiagi
Also in addition to the above query one more problem!
From the wiki page
http://wiki.osdev.org/Inline_Assembly/Examples i found out the implementation of both
inb and
outb but i'm having a problem implementing
inl
For inb its like
Code: Select all
static __inline__ unsigned char inb(unsigned short port)
{
unsigned char ret;
asm volatile ("inb %1,%0":"=a"(ret):"Nd"(port));
return ret;
}
But how do i do it for inl i've tried replacing %0 with %%eax but that doesn't work !!!
Re: accessing the network card
Posted: Wed May 12, 2010 11:20 am
by mkruk
You have to replace the inb instruction with inl and change the type of ret since an unsigned char is too small for inl (which means
in long, btw)
Also, from reading your postings I strongly suggest you to read some C and assembly tutorials
Furthermore, if you get to that point, you need to modify the pci device's control register to be able to access its io address space. If I remember correctly you have to set bit 0 for the io and bit 1 for the memory address space.
If you don't do that, you will just get all zeroes when accessing the device's address space. When I implemented my first PCI device driver I failed to realise this for hours and I only found out after reading the pci specifications
Re: accessing the network card
Posted: Wed May 12, 2010 11:55 am
by aloktiagi
Yes i got that after some time char was small for inl!!
The PCI page says that to calculate I/O base address we shud do
(BAR[x] & 0xFFFFFFFC).
Is it same as what u have said
If I remember correctly you have to set bit 0 for the io and bit 1 for the memory address space.