My code for finding PCI devices is as follows, in rust:
Code: Select all
fn get_vendor_id(bus: u16, device: u16, function: u16) -> u32 {
read_word(bus, device, function, 0)
}
fn get_device_id(bus: u16, device: u16, function: u16) -> u32 {
read_word(bus, device, function, 2)
}
fn get_class_id(bus: u16, device: u16, function: u16) -> u32 {
(read_word(bus, device, function, 0xA) & !0x00FF) >> 8
}
fn get_prog_if(bus: u16, device: u16, function: u16) -> u32 {
read_word(bus, device, function, 0x8).get_bits(8..15)
}
fn get_header_type(bus: u16, device: u16, function: u16) -> u32 {
read_word(bus, device, function, 0x0C).get_bits(16..23)
}
fn get_subclass_id(bus: u16, device: u16, function: u16) -> u32 {
(read_word(bus, device, function, 0x08) & !0xFF00)
}
fn get_status(bus: u16, device: u16, function: u16) -> u32 {
read_word(bus, device, function, 0x04).get_bits(24..31)
}
fn get_command(bus: u16, device: u16, function: u16) -> u32 {
read_word(bus, device, function, 0x04).get_bits(16..23)
}
fn get_rev(bus: u16, device: u16, function: u16) -> u32 {
read_word(bus, device, function, 0x08).get_bits(0..7)
}
This roughly translates to (in C):
Code: Select all
// This code is only provided to make the C code work properly. The syntax is a bit different in rust
int32_t get_bit(int32_t num, uint8_t bit) {
if (bit < 32) {
return (num & (1 << bit));
} else {
return -1;
}
}
int32_t get_bits(int32_t number, uint8_t start, uint8_t end) {
if (start < 32 && end <= 32 && start < end) {
// shift away high bits
int32_t bits = number << (32 - end) >> (32 - end);
// shift away low bits
return bits >> start;
} else {
return -1;
}
}
// The typedefs u8, u16, u32, u64, i8, ... map to their equivalent C types
u32 get_vendor_id(u16 bus, u16 device, u16 function) {
return read_word(bus, device, function, 0);
}
u32 get_device_id(u16 bus, u16 device, u16 function) {
return read_word(bus, device, function, 2);
}
u32 get_class_id(u16 bus, u16 device, u16 function) {
return (read_word(bus, device, function, 0xA) & !0x00FF) >> 8;
}
u32 get_prog_if(u16 bus, u16 device, u16 function) {
return get_bits(read_word(bus, device, function, 0x08), 8, 15);
}
u32 get_header_type(u16 bus, u16 device, u16 function) {
return get_bits(read_word(bus, device, function, 0x0C), 16, 23);
}
u32 get_subclass_id(u16 bus, u16 device, u16 function) {
return (read_word(bus, device, function, 0x08) & !0xFF00);
}
u32 get_status(u16 bus, u16 device, u16 function) {
return get_bits(read_word(bus, device, function, 0x04), 24, 31);
}
u32 get_command(u16 bus, u16 device, u16 function) {
return get_bits(read_word(bus, device, function, 0x04), 16, 23);
}
u32 get_rev(u16 bus, u16 device, u16 function) {
return get_bits(read_word(bus, device, function, 0x08), 0, 7);
}
I'm doing the brute-force method to find PCI devices as well. My kernel loops through the buses, slots and functions:
Code: Select all
// C (original is rust)
void probe() {
for (int bus = 0; bus < 256; bus++) {
for (int slot = 0; slot < 32; slot++) {
for (int function = 0; function < 8; function++) {
// Get vendor, device, class and subclass codes.
u32 vendor = get_vendor_id(bus, slot, function);
if (vendor == 0xFFFF) {
continue;
}
u32 device = get_device_id(bus, slot, function);
u32 class = get_class_id(bus, slot, function);
u32 subclass = get_subclass_id(bus, slot, function);
// Assumed printf function
printf(
"PCI: probe: found %s %s (%s)",
get_vendor_string(vendor),
get_device_string(device),
get_subclass_string(class, subclass)
);
// continue probe...
I get vendor strings and so on by doing something majorly inefficient, but it works for now. I'll definitely change it later though! My kernel has a file, pcidb.rs, which embeds the entire PCI ID repository as a giant switch statement. (In rust its called a match statement, and each "case" in a switch statement is called an "arm".) I know, its majorly inefficient and disgusting, which is why I'll definitely change it later!
Modifying the printf statement (in my kernel its printkln) to print device data, I get this for the HDA device:
PCI: probe: found Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller (Multimedia audio controller)
PCI: probe: codes: vendor = 8086h, device = 2668h, class = 4h, subclass = 1h, bus = 0h, slot = 3h, function = 0h
PCI: probe: Offset 8: 1, bits (4 each): 1, 0, 0, 0, 0, 0, 0, 0