Following what Linux did quite a while ago, don't generally disallow
MMCFG base addresses to live above the 4Gb boundary: New systems are
assumed to be fine, and SGI ones are, too.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
--- a/xen/arch/x86/dmi_scan.c
+++ b/xen/arch/x86/dmi_scan.c
@@ -520,6 +520,76 @@ fail: d++;
return count;
}
+/**
+ * dmi_get_date - parse a DMI date
+ * @field: data index (see enum dmi_field)
+ * @yearp: optional out parameter for the year
+ * @monthp: optional out parameter for the month
+ * @dayp: optional out parameter for the day
+ *
+ * The date field is assumed to be in the form resembling
+ * [mm[/dd]]/yy[yy] and the result is stored in the out
+ * parameters any or all of which can be omitted.
+ *
+ * If the field doesn't exist, all out parameters are set to zero
+ * and false is returned. Otherwise, true is returned with any
+ * invalid part of date set to zero.
+ *
+ * On return, year, month and day are guaranteed to be in the
+ * range of [0,9999], [0,12] and [0,31] respectively.
+ */
+bool_t __init dmi_get_date(int field, int *yearp, int *monthp, int *dayp)
+{
+ int year = 0, month = 0, day = 0;
+ bool_t exists;
+ const char *s, *e, *y;
+
+ s = field < DMI_STRING_MAX ? dmi_ident[field] : NULL;
+ exists = !!s;
+ if (!exists)
+ goto out;
+
+ /*
+ * Determine year first. We assume the date string resembles
+ * mm/dd/yy[yy] but the original code extracted only the year
+ * from the end. Keep the behavior in the spirit of no
+ * surprises.
+ */
+ y = strrchr(s, '/');
+ if (!y)
+ goto out;
+
+ y++;
+ year = simple_strtoul(y, &e, 10);
+ if (y != e && year < 100) { /* 2-digit year */
+ year += 1900;
+ if (year < 1996) /* no dates < spec 1.0 */
+ year += 100;
+ }
+ if (year > 9999) /* year should fit in %04d */
+ year = 0;
+
+ /* parse the mm and dd */
+ month = simple_strtoul(s, &e, 10);
+ if (s == e || *e != '/' || !month || month > 12) {
+ month = 0;
+ goto out;
+ }
+
+ s = e + 1;
+ day = simple_strtoul(s, &e, 10);
+ if (s == y || s == e || *e != '/' || day > 31)
+ day = 0;
+out:
+ if (yearp)
+ *yearp = year;
+ if (monthp)
+ *monthp = month;
+ if (dayp)
+ *dayp = day;
+ return exists;
+}
+
void __init dmi_end_boot(void)
{
unsigned int i;
--- a/xen/arch/x86/x86_64/acpi_mmcfg.c
+++ b/xen/arch/x86/x86_64/acpi_mmcfg.c
@@ -48,6 +48,30 @@
struct acpi_mcfg_allocation *pci_mmcfg_config;
int pci_mmcfg_config_num;
+static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
+ struct acpi_mcfg_allocation *cfg)
+{
+ int year;
+
+ if (cfg->address < 0xFFFFFFFF)
+ return 0;
+
+ if (!strcmp(mcfg->header.oem_id, "SGI") ||
+ !strcmp(mcfg->header.oem_id, "SGI2"))
+ return 0;
+
+ if (mcfg->header.revision >= 1 &&
+ dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
+ year >= 2010)
+ return 0;
+
+ printk(KERN_ERR "MCFG region for %04x:%02x-%02x at %#"PRIx64
+ " (above 4GB) ignored\n",
+ cfg->pci_segment, cfg->start_bus_number, cfg->end_bus_number,
+ cfg->address);
+ return -EINVAL;
+}
+
int __init acpi_parse_mcfg(struct acpi_table_header *header)
{
struct acpi_table_mcfg *mcfg;
@@ -82,9 +106,7 @@ int __init acpi_parse_mcfg(struct acpi_t
pci_mmcfg_config_num * sizeof(*pci_mmcfg_config));
for (i = 0; i < pci_mmcfg_config_num; ++i) {
- if (pci_mmcfg_config[i].address > 0xFFFFFFFF) {
- printk(KERN_ERR PREFIX
- "MMCONFIG not in low 4GB of memory\n");
+ if (acpi_mcfg_check_entry(mcfg, &pci_mmcfg_config[i])) {
xfree(pci_mmcfg_config);
pci_mmcfg_config_num = 0;
return -ENODEV;
--- a/xen/include/xen/dmi.h
+++ b/xen/include/xen/dmi.h
@@ -36,6 +36,7 @@ extern int dmi_check_system(struct dmi_s
extern void dmi_scan_machine(void);
extern int dmi_get_table(u32 *base, u32 *len);
extern void dmi_efi_get_table(void *);
+bool_t dmi_get_date(int field, int *yearp, int *monthp, int *dayp);
extern void dmi_end_boot(void);
#endif /* __DMI_H__ */
x86_64-mmcfg-64bit.patch
Description: Text document
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|