PCI gives strange values
PCI gives strange values
Good day! PCI gives me strange values. On 65025 devices is vendorID 3327, deviceID 0, classcode 0, subclass 0 and progIF 12. I use Virtualbox. Please what it is? My code is in https://github.com/Klaykap/LightningOS/issues/1
Re: PCI gives strange values
From a quick look at your code, I think
Should be
Or something like that.
Code: Select all
tmp = (uint16_t)((inl(0xCFC) >> ((offset & 2) * 8)) & 0xffff);
Code: Select all
tmp = (uint16_t)((inl(0xCFC) >> ((offset & 1) == 0 ? 8 : 0)) & 0xffff);
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Re: PCI gives strange values
Thank you, I change code but output is now:
vendorID 12
deviceID 12
classcode 0
subclass 12
progIF 0
on all 65025 slots.
vendorID 12
deviceID 12
classcode 0
subclass 12
progIF 0
on all 65025 slots.
Re: PCI gives strange values
Hi,
When reading the PCI space, you need to keep a few things in mind.
The read register is a dword register, but can be read as a byte, word, or dword, as well as reading any one of the bytes within the dword.
For example, the two lines below produce the exact same results:
word = inpw(PCI_DATA + 2);
word = inpd(PCI_DATA) >> 16;
Therefore, you can read any byte, word, or dword at any offset in the PCI space, with the understanding that you cannot read across a dword boundary. For example, you cannot do:
dword = inpd(PCI_DATA + 2);
expecting to read the high word of the first dword and the low word of the next dword.
With this in mind, the following lines are all valid:
byte = inpb(PCI_DATA + 0);
byte = inpb(PCI_DATA + 1);
byte = inpb(PCI_DATA + 2);
byte = inpb(PCI_DATA + 3);
word = inpw(PCI_DATA + 0);
word = inpw(PCI_DATA + 1);
word = inpw(PCI_DATA + 2);
dword = inpd(PCI_DATA + 0);
However, the following lines are *not* valid:
byte = inpb(PCI_DATA + x); // where x > 3
word = inpw(PCI_DATA + x); // where x > 2
dword = inpd(PCI_DATA + x); // where x > 0
Now, take this in to mind and how about you do the following:
Then pci_read_word() does the same thing, but for bytes. i.e.: if the word offset would cross a dword boundary, it calls pci_read_byte twice.
Do you get the idea?
If the current sized read will read across the dword boundary, call the smaller sized read twice, else just read in the sized value.
For example, a dword read from offset 2 in the config space will actually do:
How above a dword read from offset 3?
Two more things:
1) If the first function of a device returns 0xFFFF as the vendor ID, the remaining functions of this device are not valid. They, infact, might return other values, though since the first function returned 0xFFFF, these functions are to be ignored.
2) The first function has a bit in the header that states whether the remaining functions are valid. If this bit indicates there are no more functions, you must skip the remaining 7 functions while enumerating the PCI. As an example, I have an ATA device controller that will return the same data for all 8 functions read even though there is only one valid function. If your PCI enumerator didn't ignore the remaining 7 functions, you might think you have 8 ATA controllers at this device...
Does this help,
Ben
- http://www.fysnet.net/osdesign_book_series.htm
When reading the PCI space, you need to keep a few things in mind.
The read register is a dword register, but can be read as a byte, word, or dword, as well as reading any one of the bytes within the dword.
For example, the two lines below produce the exact same results:
word = inpw(PCI_DATA + 2);
word = inpd(PCI_DATA) >> 16;
Therefore, you can read any byte, word, or dword at any offset in the PCI space, with the understanding that you cannot read across a dword boundary. For example, you cannot do:
dword = inpd(PCI_DATA + 2);
expecting to read the high word of the first dword and the low word of the next dword.
With this in mind, the following lines are all valid:
byte = inpb(PCI_DATA + 0);
byte = inpb(PCI_DATA + 1);
byte = inpb(PCI_DATA + 2);
byte = inpb(PCI_DATA + 3);
word = inpw(PCI_DATA + 0);
word = inpw(PCI_DATA + 1);
word = inpw(PCI_DATA + 2);
dword = inpd(PCI_DATA + 0);
However, the following lines are *not* valid:
byte = inpb(PCI_DATA + x); // where x > 3
word = inpw(PCI_DATA + x); // where x > 2
dword = inpd(PCI_DATA + x); // where x > 0
Now, take this in to mind and how about you do the following:
Code: Select all
pci_read_dword(..., ..., offset)
begin
if (offset > 0) then
begin
return (pci_read_word(offset) << 0) | (pci_read_word(offset) << 16)
end
else
return dword
end
Do you get the idea?
If the current sized read will read across the dword boundary, call the smaller sized read twice, else just read in the sized value.
For example, a dword read from offset 2 in the config space will actually do:
Code: Select all
read_pci_dword calls:
read_pci_word(offset + 0) // offset = 2
read_pci_word(offset + 2) // offset = 2
Code: Select all
read_pci_dword calls:
read_pci_word calls
read_pci_byte(offset + 0) // offset = 3
read_pci_byte(offset + 1) // offset = 3
read_pci_word(offset + 2) // offset = 3
1) If the first function of a device returns 0xFFFF as the vendor ID, the remaining functions of this device are not valid. They, infact, might return other values, though since the first function returned 0xFFFF, these functions are to be ignored.
2) The first function has a bit in the header that states whether the remaining functions are valid. If this bit indicates there are no more functions, you must skip the remaining 7 functions while enumerating the PCI. As an example, I have an ATA device controller that will return the same data for all 8 functions read even though there is only one valid function. If your PCI enumerator didn't ignore the remaining 7 functions, you might think you have 8 ATA controllers at this device...
Does this help,
Ben
- http://www.fysnet.net/osdesign_book_series.htm
Re: PCI gives strange values
Since you didn't reply yet, either you fixed the problem and haven't been able to stop since, or you still are having problems and have pulled all your hair out thinking about it.
How are you doing?
Ben
How are you doing?
Ben
Re: PCI gives strange values
Sorry, but I did not understand as I do that the methods pci_read_* (in PCI on the wikipage is only pci_read_word) I can't program in Pascal . Please how is done in C?
Re: PCI gives strange values
Sorry, I won't write the code for you.Klakap wrote:Sorry, but I did not understand as I do that the methods pci_read_* (in PCI on the wikipage is only pci_read_word) I can't program in Pascal . Please how is done in C?
The wiki gives an excellent example of reading a word from a given address. It should be fairly simple to modify it to read a byte or a dword.
Remember, when you write the bitmap to the ADDRESS register, the PCI bus will populate the DATA register with a 32-bit value read from the dword offset specified by the bit map written to the ADDRESS register. It is up to your code to extract a byte, word, or the whole dword from this register by either reading the register as an 8-bit byte, a 16-bit word, or a 32-bit dword. The architecture allows you to read a word from DATA + 0, DATA + 1, or DATA + 2, for example. Or you can read the whole 32-bit dword then AND/SHR the result to get the smaller sized value.
However, the point is, the PCI BUS will only populate the register with DWORDs on DWORD boundaries. You cannot read a dword from PCI Config Space byte offset 2. If you wish to read a dword from this offset, you must tell the PCI bus to read the dword at offset 0, extract the word at offset 2, *and* read the dword from offset 4 (the second dword), then extract the remaining word from this value to combine to create the dword you wish to read.
Here is a figure from Chapter 2 of my USB book:
Assuming each is in little ending format:
Example 1 shows that if I wish to read a byte from PCI Config Space byte offset 20, which is the first byte of Dword 5, I must tell the PCI bus to read the dword at DWORD 5. Then I can extract the byte by either reading a byte from the register (DATA + 0, in this case), or reading the whole dword register and ANDing the 32-bit value to extract the 8-bit result.
Example 2 shows that if I wish to read a word from PCI Config Space byte offset 30, which is the higher word of Dword 7, I must tell the PCI bus to read the dword at DWORD 7. Then I can extract the word by either reading a word from the register (DATA + 2, in this case), or reading the whole dword register and SHRing the 32-bit value to extract the 16-bit result.
Example 3 shows that if I wish to read a dword from PCI Config Space byte offset 34, I *must* read from the PCI bus twice to get the result dword value. I *must* read from Dword 8, extract the high word, placing it in the low word of my result value, then I *must* read from Dword 9, extracting the low word and placing it in the high word of my resultant value.
This is quite confusing, but with a little reading and understanding, it will get quite easy, quite quickly.
My point to this and my previous post is that if you write three routines, a read_dword, a read_word, and a read_byte routine, you can call either of them with a byte offset to the value you wish to read. Then if the dword or word routine calculates that it would be reading across a dword boundary, it can call the lesser-sized routine twice to extract this value, of course knowing that a byte read will not cross a dword boundary, because you are reading a byte from a byte offset.
Therefore, if I wish to read a dword from byte offset 34, as in the example above, I call my read_dword routine with an offset value of 34. My dword routine does a:
Code: Select all
if ((offset + 4) % 4) > 0) {
or
if ((offset & 3) > 0) {
or
if (any other way to know if we would cross a boundary) {
low_word = read_word(offset + 0);
high_word = read_word(offset + 2);
return (high_word << 16) | low_word;
} else
return dword_read_from_DATA_register;
This technique lets me read a dword from any byte offset within the PCI Config space by calling only read_dword(), allowing the read_dword() routine to "farm" out the necessary 16-bit reads, then allowing read_word() "farm" out the necessary 8-bit reads.
Does this make any sense? Clear as mud?
Ben
- http://www.fysnet.net/osdesign_book_series.htm
Re: PCI gives strange values
Thank you for advice, I will try to do a driver for the PCI.