private void CheckDevice(int bus, int dev, int func) { uint vendor_devID = ReadConfig(bus, dev, func, 0); uint vendorID = vendor_devID & 0xffff; if (vendorID == 0xffff) { return; } /* Get the basic fields of the device */ uint command_status = ReadConfig(bus, dev, func, 4); uint revID_progIF_subclass_class = ReadConfig(bus, dev, func, 8); uint cacheline_latency_ht_bist = ReadConfig(bus, dev, func, 0xc); /* We have found a valid device */ uint deviceID = vendor_devID >> 16; uint classcode = (revID_progIF_subclass_class >> 24) & 0xffU; uint subclasscode = (revID_progIF_subclass_class >> 16) & 0xffU; uint prog_IF = (revID_progIF_subclass_class >> 8) & 0xffU; uint revisionID = revID_progIF_subclass_class & 0xffU; System.Diagnostics.Debugger.Log(0, "pci", bus.ToString() + ":" + dev.ToString() + ":" + func.ToString() + " : " + vendorID.ToString("X4") + ":" + deviceID.ToString("X4") + " " + classcode.ToString("X2") + ":" + subclasscode.ToString("X2") + ":" + prog_IF.ToString("X2")); DeviceDBEntry details = DeviceDB.GetDeviceDetails(new DeviceDBKey { VendorID = vendorID, DeviceID = deviceID, RevisionID = revisionID, ClassCode = classcode, SubclassCode = subclasscode, ProgIF = prog_IF }); if (details == null) { System.Diagnostics.Debugger.Log(0, "pci", "unknown device"); } else { System.Diagnostics.Debugger.Log(0, "pci", details.ToString()); if (details.DriverName != null) { /* Build a device node */ List <tysos.lib.File.Property> props = new List <tysos.lib.File.Property>(); props.Add(new tysos.lib.File.Property { Name = "driver", Value = details.DriverName }); if (details.SubdriverName != null) { props.Add(new tysos.lib.File.Property { Name = "subdriver", Value = details.SubdriverName }); } if (details.HumanDeviceName != null) { props.Add(new tysos.lib.File.Property { Name = "name", Value = details.HumanDeviceName }); } if (details.HumanManufacturerName != null) { props.Add(new tysos.lib.File.Property { Name = "manufacturer", Value = details.HumanManufacturerName }); } PCIConfiguration conf = new PCIConfiguration(CONFIG_ADDRESS, CONFIG_DATA, bus, dev, func, this, details.BAROverrides); props.Add(new tysos.lib.File.Property { Name = "pciconf", Value = conf }); if (details.ExtraResources != null) { foreach (var res in details.ExtraResources) { if (res is tysos.Resources.InterruptLine) { props.Add(new tysos.lib.File.Property { Name = "interrupt", Value = res }); } else if (res is tysos.PhysicalMemoryResource64) { props.Add(new tysos.lib.File.Property { Name = "pmem", Value = res }); } else if (res is tysos.VirtualMemoryResource64) { props.Add(new tysos.lib.File.Property { Name = "vmem", Value = res }); } else if (res is tysos.x86_64.IOResource) { props.Add(new tysos.lib.File.Property { Name = "io", Value = res }); } } } /* Is the device enumerated in ACPI too? */ int dev_acpi = dev << 16 | func; int dev_acpi_all = dev << 16 | 0xffff; if (acpinames.ContainsKey(dev_acpi)) { props.Add(new tysos.lib.File.Property { Name = "acpiname", Value = acpinames[dev_acpi] }); } if (acpinames.ContainsKey(dev_acpi_all)) { props.Add(new tysos.lib.File.Property { Name = "acpiname", Value = acpinames[dev_acpi_all] }); } // Get interrupt pin number uint conf_3c = conf.ReadConfig(0x3c); uint pin = (conf_3c >> 8) & 0xffU; if (pin != 0) { int int_pin = (int)(pin - 1); if (prts.ContainsKey(dev_acpi)) { props.Add(new tysos.lib.File.Property { Name = "interrupt", Value = prts[dev_acpi][int_pin] }); } if (prts.ContainsKey(dev_acpi_all)) { props.Add(new tysos.lib.File.Property { Name = "interrupt", Value = prts[dev_acpi_all][int_pin] }); } } /* Generate a unique name for the device */ int dev_no = 0; StringBuilder sb = new StringBuilder(details.DriverName); if (details.SubdriverName != null) { sb.Append("_"); sb.Append(details.SubdriverName); } string base_dev = sb.ToString(); if (next_device_id.ContainsKey(base_dev)) { dev_no = next_device_id[base_dev]; } sb.Append("_"); sb.Append(dev_no.ToString()); next_device_id[base_dev] = dev_no + 1; string dev_name = sb.ToString(); children[dev_name] = props; foreach (var prop in props) { System.Diagnostics.Debugger.Log(0, "pci", " " + prop.Name + ": " + prop.Value.ToString()); } } } /* If header type == 0x80, it is a multifunction device */ uint header_type = (cacheline_latency_ht_bist >> 16) & 0xffU; if (header_type == 0x80 && func == 0) { for (int subfunc = 1; subfunc < 8; subfunc++) { CheckDevice(bus, dev, subfunc); } } }
public RPCResult <tysos.RangeResource> GetBAR(PCIConfiguration conf, int bar_no) { /* Get the requested BAR of the device passed. * If its base is zero, but length is not, we have to allocate it * somewhere */ /* Ensure the device is enumerated by this bridge */ if (conf.hb != this) { return(null); } /* Ensure its a valid BAR index. For header type 0, max_bar is 6, * for header 1 its 2 and for others its 0 */ uint header_type = ReadConfig(conf.bus, conf.dev, conf.func, 0xc); header_type >>= 16; header_type &= 0xffU; int max_bar = 0; if (header_type == 0) { max_bar = 6; } else if (header_type == 1) { max_bar = 2; } if (bar_no >= max_bar) { return(null); } /* See if we have a valid bar override */ if (conf.bars != null && bar_no < conf.bars.Count) { BAROverride bar_override = conf.bars[bar_no]; switch (bar_override.Type) { case 0: return(pmems.AllocFixed(bar_override.Value, bar_override.Length, true)); case 1: return(ios.AllocFixed(bar_override.Value, bar_override.Length, true)); } } /* If bar_no >= 1, read the previous BAR to ensure we're not * trying to read half way into a 64-bit one */ if (bar_no >= 1) { uint prev_bar = ReadConfig(conf.bus, conf.dev, conf.func, (bar_no - 1) * 4 + 0x10); if ((prev_bar & 0x7) == 0x4) { /* Previous bar is a 64 bit memory register */ return(null); } } /* Read the current value of the bar */ int bar_addr = bar_no * 4 + 0x10; uint bar = ReadConfig(conf.bus, conf.dev, conf.func, bar_addr); if ((bar & 0x1) == 0) { // Memory register ulong base_addr = 0; ulong length = 0; switch (bar & 0x7) { case 0: // 32 bit address base_addr = bar & 0xfffffff0U; /* To get length, write all 1s, read length, mask out type bits * and write the original value back */ WriteConfig(conf.bus, conf.dev, conf.func, bar_addr, 0xffffffffU); length = ReadConfig(conf.bus, conf.dev, conf.func, bar_addr); length &= 0xfffffff0U; WriteConfig(conf.bus, conf.dev, conf.func, bar_addr, bar); unchecked { length = ~length; length++; } length &= 0xffffffffU; break; case 2: // 16 bit address base_addr = bar & 0xfff0U; WriteConfig(conf.bus, conf.dev, conf.func, bar_addr, 0xffffU); length = ReadConfig(conf.bus, conf.dev, conf.func, bar_addr); length &= 0xfff0U; WriteConfig(conf.bus, conf.dev, conf.func, bar_addr, bar); unchecked { length = ~length; length++; } length &= 0xffffU; break; case 4: // 64 bit address int next_bar = bar_no + 1; int next_bar_addr = next_bar * 4 + 0x10; if (next_bar >= max_bar) { return(null); } ulong next_bar_val = ReadConfig(conf.bus, conf.dev, conf.func, next_bar_addr); base_addr = bar & 0xfffffff0U; base_addr |= (next_bar_val << 32); WriteConfig(conf.bus, conf.dev, conf.func, bar_addr, 0xffffffffU); length = ReadConfig(conf.bus, conf.dev, conf.func, bar_addr); length &= 0xfffffff0U; WriteConfig(conf.bus, conf.dev, conf.func, bar_addr, bar); WriteConfig(conf.bus, conf.dev, conf.func, next_bar_addr, 0xffffffffU); ulong next_length = ReadConfig(conf.bus, conf.dev, conf.func, next_bar_addr); length |= (next_length << 32); WriteConfig(conf.bus, conf.dev, conf.func, next_bar_addr, (uint)next_bar_val); unchecked { length = ~length; length++; } break; } if (length == 0) { return(null); } tysos.PhysicalMemoryResource64 pmem = pmems.AllocFixed(base_addr, length, true); if (pmem != null) { return(pmem); } // TODO: allocate a chunk of physical address space for the device pmem = pmems.Alloc(length, 0x1000, (bar & 0x7) != 0x4); if (pmem == null) { System.Diagnostics.Debugger.Log(0, "pci", "could not allocate physical memory for BAR"); return(null); } System.Diagnostics.Debugger.Log(0, "pci", "allocated " + pmem.ToString() + " for BAR " + bar_no.ToString()); throw new NotImplementedException(); } else { // IO register uint base_addr = bar & 0xfffffffcU; /* To get length, write all 1s, read length, mask out type bits * and write the original value back */ WriteConfig(conf.bus, conf.dev, conf.func, bar_addr, 0xffffffffU); uint length = ReadConfig(conf.bus, conf.dev, conf.func, bar_addr); length &= 0xfffffffcU; WriteConfig(conf.bus, conf.dev, conf.func, bar_addr, bar); unchecked { length = ~length; length++; } length &= 0xffffffffU; tysos.x86_64.IOResource io = ios.AllocFixed(base_addr, length, true); if (io != null) { return(io); } if (length == 0) { return(null); } // TODO: allocate a chunk of IO space for the device throw new NotImplementedException(); } }