Ejemplo n.º 1
0
        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);
                }
            }
        }
Ejemplo n.º 2
0
        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();
            }
        }