/* PCIe MMCFG */ static void mch_update_pciexbar(MCHPCIState *mch) { PCIDevice *pci_dev = PCI_DEVICE(mch); BusState *bus = qdev_get_parent_bus(DEVICE(mch)); PCIExpressHost *pehb = PCIE_HOST_BRIDGE(bus->parent); uint64_t pciexbar; int enable; uint64_t addr; uint64_t addr_mask; uint32_t length; pciexbar = pci_get_quad(pci_dev->config + MCH_HOST_BRIDGE_PCIEXBAR); enable = pciexbar & MCH_HOST_BRIDGE_PCIEXBAREN; addr_mask = MCH_HOST_BRIDGE_PCIEXBAR_ADMSK; switch (pciexbar & MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK) { case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M: length = 256 * 1024 * 1024; break; case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M: length = 128 * 1024 * 1024; addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK | MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK; break; case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M: length = 64 * 1024 * 1024; addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK; break; case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD: default: abort(); } addr = pciexbar & addr_mask; pcie_host_mmcfg_update(pehb, enable, addr, length); /* Leave enough space for the MCFG BAR */ /* * TODO: this matches current bios behaviour, but it's not a power of two, * which means an MTRR can't cover it exactly. */ if (enable) { range_set_bounds(&mch->pci_hole, addr + length, IO_APIC_DEFAULT_ADDRESS - 1); } else { range_set_bounds(&mch->pci_hole, MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT, IO_APIC_DEFAULT_ADDRESS - 1); } }
static void string_output_append(StringOutputVisitor *sov, int64_t a) { Range *r = g_malloc0(sizeof(*r)); range_set_bounds(r, a, a); sov->ranges = range_list_insert(sov->ranges, r); }
static void q35_host_initfn(Object *obj) { Q35PCIHost *s = Q35_HOST_DEVICE(obj); PCIHostState *phb = PCI_HOST_BRIDGE(obj); memory_region_init_io(&phb->conf_mem, obj, &pci_host_conf_le_ops, phb, "pci-conf-idx", 4); memory_region_init_io(&phb->data_mem, obj, &pci_host_data_le_ops, phb, "pci-conf-data", 4); object_initialize(&s->mch, sizeof(s->mch), TYPE_MCH_PCI_DEVICE); object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL); qdev_prop_set_uint32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0)); qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int", q35_host_get_pci_hole_start, NULL, NULL, NULL, NULL); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "int", q35_host_get_pci_hole_end, NULL, NULL, NULL, NULL); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "int", q35_host_get_pci_hole64_start, NULL, NULL, NULL, NULL); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int", q35_host_get_pci_hole64_end, NULL, NULL, NULL, NULL); object_property_add(obj, PCIE_HOST_MCFG_SIZE, "int", q35_host_get_mmcfg_size, NULL, NULL, NULL, NULL); object_property_add_link(obj, MCH_HOST_PROP_RAM_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.ram_memory, qdev_prop_allow_set_link_before_realize, 0, NULL); object_property_add_link(obj, MCH_HOST_PROP_PCI_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.pci_address_space, qdev_prop_allow_set_link_before_realize, 0, NULL); object_property_add_link(obj, MCH_HOST_PROP_SYSTEM_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.system_memory, qdev_prop_allow_set_link_before_realize, 0, NULL); object_property_add_link(obj, MCH_HOST_PROP_IO_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.address_space_io, qdev_prop_allow_set_link_before_realize, 0, NULL); /* Leave enough space for the biggest MCFG BAR */ /* TODO: this matches current bios behaviour, but * it's not a power of two, which means an MTRR * can't cover it exactly. */ range_set_bounds(&s->mch.pci_hole, MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT + MCH_HOST_BRIDGE_PCIEXBAR_MAX, IO_APIC_DEFAULT_ADDRESS - 1); }
static int parse_str(StringInputVisitor *siv, const char *name, Error **errp) { char *str = (char *) siv->string; long long start, end; Range *cur; char *endptr; if (siv->ranges) { return 0; } do { errno = 0; start = strtoll(str, &endptr, 0); if (errno == 0 && endptr > str) { if (*endptr == '\0') { cur = g_malloc0(sizeof(*cur)); range_set_bounds(cur, start, start); siv->ranges = range_list_insert(siv->ranges, cur); cur = NULL; str = NULL; } else if (*endptr == '-') { str = endptr + 1; errno = 0; end = strtoll(str, &endptr, 0); if (errno == 0 && endptr > str && start <= end && (start > INT64_MAX - 65536 || end < start + 65536)) { if (*endptr == '\0') { cur = g_malloc0(sizeof(*cur)); range_set_bounds(cur, start, end); siv->ranges = range_list_insert(siv->ranges, cur); cur = NULL; str = NULL; } else if (*endptr == ',') { str = endptr + 1; cur = g_malloc0(sizeof(*cur)); range_set_bounds(cur, start, end); siv->ranges = range_list_insert(siv->ranges, cur); cur = NULL; } else { goto error; } } else { goto error; } } else if (*endptr == ',') { str = endptr + 1; cur = g_malloc0(sizeof(*cur)); range_set_bounds(cur, start, start); siv->ranges = range_list_insert(siv->ranges, cur); cur = NULL; } else { goto error; } } else { goto error; } } while (str); return 0; error: g_list_foreach(siv->ranges, free_range, NULL); g_list_free(siv->ranges); siv->ranges = NULL; error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", "an int64 value or range"); return -1; }
void qemu_set_dfilter_ranges(const char *filter_spec, Error **errp) { gchar **ranges = g_strsplit(filter_spec, ",", 0); int i; if (debug_regions) { g_array_unref(debug_regions); debug_regions = NULL; } debug_regions = g_array_sized_new(FALSE, FALSE, sizeof(Range), g_strv_length(ranges)); for (i = 0; ranges[i]; i++) { const char *r = ranges[i]; const char *range_op, *r2, *e; uint64_t r1val, r2val, lob, upb; struct Range range; range_op = strstr(r, "-"); r2 = range_op ? range_op + 1 : NULL; if (!range_op) { range_op = strstr(r, "+"); r2 = range_op ? range_op + 1 : NULL; } if (!range_op) { range_op = strstr(r, ".."); r2 = range_op ? range_op + 2 : NULL; } if (!range_op) { error_setg(errp, "Bad range specifier"); goto out; } if (qemu_strtoull(r, &e, 0, &r1val) || e != range_op) { error_setg(errp, "Invalid number to the left of %.*s", (int)(r2 - range_op), range_op); goto out; } if (qemu_strtoull(r2, NULL, 0, &r2val)) { error_setg(errp, "Invalid number to the right of %.*s", (int)(r2 - range_op), range_op); goto out; } switch (*range_op) { case '+': lob = r1val; upb = r1val + r2val - 1; break; case '-': upb = r1val; lob = r1val - (r2val - 1); break; case '.': lob = r1val; upb = r2val; break; default: g_assert_not_reached(); } if (lob > upb) { error_setg(errp, "Invalid range"); goto out; } range_set_bounds(&range, lob, upb); g_array_append_val(debug_regions, range); } out: g_strfreev(ranges); }