Index: cbv2/src/devices/device.c
===================================================================
--- cbv2.orig/src/devices/device.c
+++ cbv2/src/devices/device.c
@@ -43,12 +43,6 @@ struct device *all_devices = &dev_root;
 /** Pointer to the last device */
 extern struct device **last_dev_p;
 
-/** The upper limit of MEM resource of the devices.
- * Reserve 20M for the system */
-#define DEVICE_MEM_HIGH 0xFEBFFFFFUL
-/** The lower limit of IO resource of the devices.
- * Reserve 4k for ISA/Legacy devices */
-#define DEVICE_IO_START 0x1000
 
 /**
  * @brief Allocate a new device structure.
@@ -163,8 +157,8 @@ struct pick_largest_state {
 	int seen_last;
 };
 
-static void pick_largest_resource(void *gp,
-				  struct device *dev, struct resource *resource)
+static void pick_largest_resource(void *gp, struct device *dev,
+				  struct resource *resource)
 {
 	struct pick_largest_state *state = gp;
 	struct resource *last;
@@ -251,7 +245,7 @@ void compute_allocate_resource(struct bu
 	min_align = 0;
 	base = bridge->base;
 
-	printk_spew("%s compute_allocate_resource %s: base: %08Lx size: %08Lx align: %d gran: %d\n",
+	printk_debug("%s compute_allocate_resource %s: base: %08Lx size: %08Lx align: %d gran: %d\n",
 		dev_path(bus->dev),
 		(bridge->flags & IORESOURCE_IO)? "io":
 		(bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
@@ -299,11 +293,13 @@ void compute_allocate_resource(struct bu
 		if (bridge->limit > resource->limit) {
 			bridge->limit = resource->limit;
 		}
-#warning This heuristic should be replaced by real devices with fixed resources.
-		/* Artificially deny limits between DEVICE_MEM_HIGH and 0xffffffff */
-		if ((bridge->limit > DEVICE_MEM_HIGH)
-		    && (bridge->limit <= 0xffffffff)) {
-			bridge->limit = DEVICE_MEM_HIGH;
+
+		/* Warn if it looks like APICs aren't declared. */
+		if ((resource->limit == 0xffffffff) &&
+		    (resource->flags & IORESOURCE_ASSIGNED)) {
+			printk_err("Resource limit looks wrong! (no APIC?)\n");
+			printk_err("%s %02lx limit %08Lx\n", dev_path(dev),
+			           resource->index, resource->limit);
 		}
 
 		if (resource->flags & IORESOURCE_IO) {
@@ -373,6 +369,127 @@ void compute_allocate_resource(struct bu
 #define MEM_TYPE (IORESOURCE_MEM)
 #define IO_TYPE (IORESOURCE_IO)
 
+struct constraints {
+	struct resource pref, io, mem;
+};
+
+static void constrain_resources(struct device *dev, struct constraints* limits)
+{
+	struct device *child;
+	struct resource *res;
+	struct resource *lim;
+	int i;
+
+	printk_spew("%s: %s\n", __func__, dev_path(dev));
+
+	/* Constrain limits based on the fixed resources of this device. */
+	for (i = 0; i < dev->resources; i++) {
+		res = &dev->resource[i];
+		if (!(res->flags & IORESOURCE_FIXED))
+			continue;
+
+		/* PREFETCH, MEM, or I/O - skip any others. */
+		if ((res->flags & MEM_MASK) == PREF_TYPE)
+			lim = &limits->pref;
+		else if ((res->flags & MEM_MASK) == MEM_TYPE)
+			lim = &limits->mem;
+		else if ((res->flags & IO_MASK) == IO_TYPE)
+			lim = &limits->io;
+		else
+			continue;
+
+		/* Is it already outside the limits? */
+		if (res->size && (((res->base + res->size -1) < lim->base) ||
+				  (res->base > lim->limit)))
+			continue;
+
+		/* Choose to be above or below fixed resources.  This
+		 * check is signed so that "negative" amounts of space
+		 * are handled correctly.
+		 */
+		if ((signed long long)(lim->limit - (res->base + res->size -1)) >
+		    (signed long long)(res->base - lim->base))
+			lim->base = res->base + res->size;
+		else
+			lim->limit = res->base -1;
+	}
+
+	/* Descend into every enabled child and look for fixed resources. */
+	for (i = 0; i < dev->links; i++)
+		for (child = dev->link[i].children; child;
+		     child = child->sibling)
+			if (child->enabled)
+				constrain_resources(child, limits);
+}
+
+static void avoid_fixed_resources(struct device *dev)
+{
+	struct constraints limits;
+	struct resource *res;
+	int i;
+
+	printk_spew("%s: %s\n", __func__, dev_path(dev));
+	/* Initialize constraints to maximum size. */
+
+	limits.pref.base = 0;
+	limits.pref.limit = 0xffffffffffffffffULL;
+	limits.io.base = 0;
+	limits.io.limit = 0xffffffffffffffffULL;
+	limits.mem.base = 0;
+	limits.mem.limit = 0xffffffffffffffffULL;
+
+	/* Constrain the limits to dev's initial resources. */
+	for (i = 0; i < dev->resources; i++) {
+		res = &dev->resource[i];
+		if ((res->flags & IORESOURCE_FIXED))
+			continue;
+		printk_spew("%s:@%s %02lx limit %08Lx\n", __func__,
+			     dev_path(dev), res->index, res->limit);
+		if ((res->flags & MEM_MASK) == PREF_TYPE &&
+		    (res->limit < limits.pref.limit))
+			limits.pref.limit = res->limit;
+		if ((res->flags & MEM_MASK) == MEM_TYPE &&
+		    (res->limit < limits.mem.limit))
+			limits.mem.limit = res->limit;
+		if ((res->flags & IO_MASK) == IO_TYPE &&
+		    (res->limit < limits.io.limit))
+			limits.io.limit = res->limit;
+	}
+
+	/* Look through the tree for fixed resources and update the limits. */
+	constrain_resources(dev, &limits);
+
+	/* Update dev's resources with new limits. */
+	for (i = 0; i < dev->resources; i++) {
+		struct resource *lim;
+		res = &dev->resource[i];
+
+		if ((res->flags & IORESOURCE_FIXED))
+			continue;
+
+		/* PREFETCH, MEM, or I/O - skip any others. */
+		if ((res->flags & MEM_MASK) == PREF_TYPE)
+			lim = &limits.pref;
+		else if ((res->flags & MEM_MASK) == MEM_TYPE)
+			lim = &limits.mem;
+		else if ((res->flags & IO_MASK) == IO_TYPE)
+			lim = &limits.io;
+		else
+			continue;
+
+		printk_spew("%s2: %s@%02lx limit %08Lx\n", __func__,
+			     dev_path(dev), res->index, res->limit);
+		printk_spew("\tlim->base %08Lx lim->limit %08Lx\n",
+			     lim->base, lim->limit);
+
+		/* Is the resource outside the limits? */
+		if (lim->base > res->base)
+			res->base = lim->base;
+		if (res->limit > lim->limit)
+			res->limit = lim->limit;
+	}
+}
+
 #if CONFIG_CONSOLE_VGA == 1
 device_t vga_pri = 0;
 static void allocate_vga_resource(void)
@@ -621,8 +738,7 @@ void dev_enumerate(void)
  * requried by each device. In the second pass, the resources ranges are
  * relocated to their final position and stored to the hardware.
  *
- * I/O resources start at DEVICE_IO_START and grow upward. MEM resources start
- * at DEVICE_MEM_HIGH and grow downward.
+ * I/O resources grow upward. MEM resources grow downward.
  *
  * Since the assignment is hierarchical we set the values into the dev_root
  * struct.
@@ -650,6 +766,7 @@ void dev_configure(void)
 	printk_info("Done reading resources.\n");
 
 	print_resource_tree(root, BIOS_DEBUG, "After reading.");
+
 	/* Compute resources for all domains. */
 	for (child = root->link[0].children; child; child = child->sibling) {
 		if (!(child->path.type == DEVICE_PATH_PCI_DOMAIN))
@@ -676,9 +793,13 @@ void dev_configure(void)
 		}
 	}
 
-	/* Now we need to adjust the resources. The issue is that mem grows
-	 * downward. Reallocate the MEM resources with the highest addresses
-	 * I can manage.
+	/* For all domains. */
+	for (child = root->link[0].children; child; child=child->sibling)
+		if (child->path.type == DEVICE_PATH_PCI_DOMAIN)
+			avoid_fixed_resources(child);
+
+	/* Now we need to adjust the resources. MEM resources need to start at
+	 * the highest address managable.
 	 */
 	for (child = root->link[0].children; child; child = child->sibling) {
 		if (child->path.type != DEVICE_PATH_PCI_DOMAIN)
