Page 1 of 2
PCI
Posted: Wed May 05, 2010 10:54 am
by lemonyii
hi again,
i'm starting working on my pci code now. i read some by searching here and
http://wiki.osdev.org/PCI#Class_Codes
and i write some code myself. but all the vendor&device id except the first are 0xffffffff and all the class are 0.
what's wrong with my code? did i missed smth?
Code: Select all
extern i64 pci_init(){
register u64 i,j,val;
for(i=0x80000000; i<0x80ffff00; i+=0x100){
outdword(0xCF8, i);
val = indword(0xCFC);
if(val == 0xffffffff) break;
outdword(0xCF8, i+0x08);
val = indword(0xCFC);
val >>= 24;
j = 0;
while(val!=pci_class_table[j].class && pci_class_table[j].class) j++;
if(pci_class_table[j].class){
printk(COLOR_FG, pci_class_table[j].dscrpt);
printk(COLOR_FG, L"\n");
}
}
return 0;
}
thx
Re: PCI
Posted: Wed May 05, 2010 11:06 am
by Combuster
Basic data flow examination shows that the first unoccupied slot stops the code, and that you are not printing the class code.
Re: PCI
Posted: Wed May 05, 2010 11:27 am
by lemonyii
Combuster wrote:Basic data flow examination shows that the first unoccupied slot stops the code, and that you are not printing the class code.
do you mean
if i quote this line, it will all result in class = 0.
Re: PCI
Posted: Wed May 05, 2010 4:11 pm
by Combuster
Did you ever consider that
neither alternative is correct?
I suggest you practice some debugging skills. Homework: implement a red-black tree in userspace without asking for help. It's a first year's assignment at the local college, and it should teach you how to solve problems with non-trivial code. You will keep getting stuck in OS development if you can't systematically trace the origin of a bug.
Re: PCI
Posted: Wed May 05, 2010 7:34 pm
by gerryg400
Do you know what break does?
- gerryg400
Re: PCI
Posted: Wed May 05, 2010 10:52 pm
by lemonyii
Homework: implement a red-black tree in userspace without asking for help. It's a first year's assignment at the local college,
in fact it IS the first year of my college
but i did this when i was 15 or 16.
i think the reason why i got faults is not my code, but the way i understand PCI.
as to the
break, i remember a book referred that if you got 0xffffffff in vendor id and device id, it is a null slot and you may regard it as the end of you emuration.
and i think that it does not matter if i emurate by BFS or DFS if a check all the devices, right?
thx
Re: PCI
Posted: Wed May 05, 2010 11:56 pm
by zity
lemonyii wrote:as to the break, i remember a book referred that if you got 0xffffffff in vendor id and device id, it is a null slot and you may regard it as the end of you emuration.
Yes 0xFFFF (or even 0x0 on some broken boards) is an empty slot, but you should NOT stop enumerate. Just because you hit an empty slot doesn't mean that the rest of the slots are empty too.
Re: PCI
Posted: Wed May 05, 2010 11:59 pm
by lemonyii
but why do i still got all class=0 with that line deleted? should i do something else?
Re: PCI
Posted: Thu May 06, 2010 12:07 am
by Neolander
What zity says is that if you hit an empty slot, the correct thing to do is to move to the next item, not to stop enumerating slots, because if slot n is empty it does not mean that slot n+1 will be empty too. break means getting out of a for() or a while() statement. With break, the implemented behavior is "if slot n is empty, stop searching".
What you meant is probably continue, which actually implements "if slot n is empty, ignore it and check slot n+1".
However, I don't know about PCI, it's just some intuitive analysis of the various posts around here, so I may be misunderstood.
Re: PCI
Posted: Thu May 06, 2010 12:09 am
by Brendan
Hi,
lemonyii wrote:as to the break, i remember a book referred that if you got 0xffffffff in vendor id and device id, it is a null slot and you may regard it as the end of you emuration.
and i think that it does not matter if i emurate by BFS or DFS if a check all the devices, right?
thx
For PCI there's up to 256 buses, up to 32 devices per bus and up to 8 functions per device. If you scan all functions in all devices on all buses it'll add up to 65536 checks and take far too long (because even for PCI devices, accessing I/O ports isn't fast), and in some cases you'll get wrong information for using information that doesn't exist (e.g. trying to get information for a device's second function when the device is a "single function" device).
For PCI devices, there's a flag in configuration space (bit 7 in the "Header Type" field) that says if the device is a multi-function device or not. If this bit isn't set then there's only one function and you don't need to check for any more (and shouldn't attempt to check for more functions). If the bit is set, then you check the functions in order and stop at the first unimplemented function.
For the PCI buses, there's host controller/s and PCI bridges. You start checking with the host controller/s PCI bus number, and when you find a PCI bridge you find the "secondary bus number" from it's configuration space and scan that PCI bus too. In that way you discover all PCI buses without checking any PCI buses that don't exist. The first PCI host controller is always "bus 0, device 0, function 0", and if this device is a multi-function device then additional host controllers will be part of the same device.
For devices within a bus, you do have to check all 32 of them.
It's usually easier to use at least 2 pieces of code for this - one piece to scan each device on a specific bus and determine if each device is multi-function or not, and one to determine if a specific function on a specific device on a specific bus is a PCI bridge or host controller (and call the first "scan_bus(secondary_bus_number)" piece of code if it is).
For example:
Code: Select all
void scan_PCI_bus(uint8_t bus_number) {
uint8_t device_number;
uint8_t function_number;
for(device_number = 0; device_number < 32; device_number++) {
if( device_exists ) {
function_number = 0;
if( device_is_multifunction ) {
while( (handle_PCI_function(bus_number, device_number, function_number) == 0) && (function_number < 7) {
function_number++;
}
} else { // Device is single-function
handle_PCI_function(bus_number, device_number, function_number);
}
}
}
}
int handle_PCI_function(uint8_t bus_number, uint8_t device_number, uint8_t function_number) {
uint8_t secondary_bus_number;
if( function_exists ) {
// Do other stuff here (display information about the device??)
if( (device_is_host_controller) || (device_is_PCI_to_PCI_bridge) ) {
secondary_bus_number = get_secondary_bus_number(bus_number, device_number, function_number);
scan_PCI_bus(secondary_bus_number);
}
return 0;
} else {
return 1;
}
}
Cheers,
Brendan
Re: PCI
Posted: Thu May 06, 2010 1:51 am
by lemonyii
thx you all above!
i can read out many none zero class in qemu and vmware now.(but not in bochs
)the next thing i got to do is to identify them.
is the class list at
http://wiki.osdev.org/PCI#Class_Codes the latest? i built a table according to it.
one more question:
(generally speaking) is there much difference between devices(of same subclass) of different vendor?
say, can i use a same driver for device of different vendor?
or what kind of device should write very(above 20%) different code?
thx
Re: PCI
Posted: Thu May 06, 2010 6:25 am
by lemonyii
http://wiki.osdev.org/PCI#Class_Codes
It seems that there is a little fault in SubClass Codes Table:
see CLASS 0x06, there are two subclass 0x00, one of which is PCI-to-PCI bridge,
i think the subclass should be 0x04 right?
Re: PCI
Posted: Thu May 06, 2010 7:38 am
by lemonyii
i can read pci configuration header now.
but i got a few devices in vmware and qemu,even less in bochs.
i dont care other things but IOAPIC, because i hope to configure it without ACPI but through PCI. is it possible to do this?
will it be much more on real machine? how many do you often get?
in vmware:
- inqemu
in qemu:
- in qemu
Re: PCI
Posted: Thu May 06, 2010 7:49 am
by zity
Normally emulators don't have more than a few PCI devices, so it looks fine.
The only connection between the I/O APIC and the PCI bus is that the I/O APIC receives the interrupts from the PCI devices. In other words, you cannot initialize the I/O APIC though the PCI bus, since the I/O APIC is not a part of the PCI bus.
To configure the I/O APIC, you either have to parse the ACPI or the MP tables.
Re: PCI
Posted: Thu May 06, 2010 7:54 am
by lemonyii
so could i use device in pci mode without IOAPIC?
and where to parse the ACPI or MP table?
i do have little knowledge about ACPI.
thx