hi
i am currently reading up on pci device enumeration and came across the wiki article http://wiki.osdev.org/PCI.
It mentions the OUTL and INPL instructions, and I cant find anywhere an explanation of these instructions
they sound like they read and write double word values from specific ports, but that interpretation doesnt really make sense with the function given as an example (pciConfigReadWord), because after reading from the port, the value read is cast to a word (unsigned short), so I am asking myself, why on earth would i first use a special instruction to read a double word and then cast that value to a word again?
inpl instruction???
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
Re: inpl instruction???
Hi,
As an example, the wiki shows one function for reading one word. It could (but doesn't) show several similar functions, like this:
Of course if you implement "pciConfigReadDword()" first, then you can use it as the basis of the other functions. For example:
The alternative (which IMHO is probably better anyway) is to only provide the "pciConfigReadDword()" function. That way if the caller wants (for e.g.) the Device ID and the Vendor ID, then they don't make the mistake of using "pciConfigReadWord()" twice (and reading the same dword from PCI configuration space twice, when only one read is needed).
To be honest, I'd probably implement the abstraction more like this:
Of course I'd also consider using function pointers to avoid those "if/else" statements (but they're ugly in C, so I didn't bother for the example above).
Cheers,
Brendan
For PCI configuration space, you can only read dwords. Therefore, if you really want to read a word instead, then you have to read a dword and discard half of it.sancho1980 wrote:i am currently reading up on pci device enumeration and came across the wiki article http://wiki.osdev.org/PCI.
It mentions the OUTL and INPL instructions, and I cant find anywhere an explanation of these instructions
they sound like they read and write double word values from specific ports, but that interpretation doesnt really make sense with the function given as an example (pciConfigReadWord), because after reading from the port, the value read is cast to a word (unsigned short), so I am asking myself, why on earth would i first use a special instruction to read a double word and then cast that value to a word again?
As an example, the wiki shows one function for reading one word. It could (but doesn't) show several similar functions, like this:
Code: Select all
unsigned long long pciConfigReadQword (unsigned short bus, unsigned short slot, unsigned short func, unsigned short offset);
unsigned int pciConfigReadDword (unsigned short bus, unsigned short slot, unsigned short func, unsigned short offset);
unsigned short pciConfigReadWord (unsigned short bus, unsigned short slot, unsigned short func, unsigned short offset);
unsigned char pciConfigReadByte (unsigned short bus, unsigned short slot, unsigned short func, unsigned short offset);
Code: Select all
unsigned short pciConfigReadWord (unsigned short bus, unsigned short slot, unsigned short func, unsigned short offset)
{
if(offset & 0x02) return (unsigned short) ( (pciConfigReadDword(bus, slot, func, offset & 0xFC) >> 16) & 0xFFFF);
else return (unsigned short) (pciConfigReadDword(bus, slot, func, offset & 0xFC) & 0xFFFF);
}
To be honest, I'd probably implement the abstraction more like this:
Code: Select all
typedef uint64_t PCI_address;
PCI_address getPCIaddress(uint8_t bus, uint8_t device, uint8_t func) {
if(PCI_access_mechanism == PCI_CONF_MECH_1) {
return ((PCI_function_ID)bus << 16) | ((PCI_function_ID)device << 11) | ((PCI_function_ID)func << 8) | ((PCI_function_ID)0x80000000);
} else if(PCI_access_mechanism == PCI_CONF_MECH_2) {
return /* code for PCI access mechanism #2 here */
} else if(PCI_access_mechanism == PCI_CONF_MECH_EXTENDED) {
return /* code for PCI express extended access mechanism here */
} else {
kernelPanic("Attempt to use unknown PCI access mechanism");
}
};
uint32_t pciConfigReadDword(PCI_address address, uint16_t offset) {
if( (offset & 0x0003) != 0) {
kernelPanic("Attempt to use bad PCI configuration space offset");
}
if(PCI_access_mechanism == PCI_CONF_MECH_1) {
sysOutLong (0xCF8, address | offset);
return sysInLong (0xCFC);
} else if(PCI_access_mechanism == PCI_CONF_MECH_2) {
return /* code for PCI access mechanism #2 here */
} else if(PCI_access_mechanism == PCI_CONF_MECH_EXTENDED) {
return /* code for PCI express extended access mechanism here */
} else {
kernelPanic("Attempt to use unknown PCI access mechanism");
}
}
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.