Author: jhb
Date: Fri Sep 25 15:08:26 2009
New Revision: 197484
URL: http://svn.freebsd.org/changeset/base/197484

Log:
  MFC 197410:
  - Split the logic to parse an SMAP entry out into a separate function on
    amd64 similar to i386.  This fixes a bug on amd64 where overlapping
    entries would not cause the SMAP parsing to stop.
  - Change the SMAP parsing code to do a sorted insertion into physmap[]
    instead of an append to support systems with out-of-order SMAP entries.
  
  Approved by:  re (kib)

Modified:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/amd64/machdep.c
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)
  stable/8/sys/i386/i386/machdep.c

Modified: stable/8/sys/amd64/amd64/machdep.c
==============================================================================
--- stable/8/sys/amd64/amd64/machdep.c  Fri Sep 25 14:58:30 2009        
(r197483)
+++ stable/8/sys/amd64/amd64/machdep.c  Fri Sep 25 15:08:26 2009        
(r197484)
@@ -1192,6 +1192,77 @@ isa_irq_pending(void)
 
 u_int basemem;
 
+static int
+add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp)
+{
+       int i, insert_idx, physmap_idx;
+
+       physmap_idx = *physmap_idxp;
+
+       if (boothowto & RB_VERBOSE)
+               printf("SMAP type=%02x base=%016lx len=%016lx\n",
+                   smap->type, smap->base, smap->length);
+
+       if (smap->type != SMAP_TYPE_MEMORY)
+               return (1);
+
+       if (smap->length == 0)
+               return (0);
+
+       /*
+        * Find insertion point while checking for overlap.  Start off by
+        * assuming the new entry will be added to the end.
+        */
+       insert_idx = physmap_idx + 2;
+       for (i = 0; i <= physmap_idx; i += 2) {
+               if (smap->base < physmap[i + 1]) {
+                       if (smap->base + smap->length <= physmap[i]) {
+                               insert_idx = i;
+                               break;
+                       }
+                       if (boothowto & RB_VERBOSE)
+                               printf(
+                   "Overlapping memory regions, ignoring second region\n");
+                       return (1);
+               }
+       }
+
+       /* See if we can prepend to the next entry. */
+       if (insert_idx <= physmap_idx &&
+           smap->base + smap->length == physmap[insert_idx]) {
+               physmap[insert_idx] = smap->base;
+               return (1);
+       }
+
+       /* See if we can append to the previous entry. */
+       if (insert_idx > 0 && smap->base == physmap[insert_idx - 1]) {
+               physmap[insert_idx - 1] += smap->length;
+               return (1);
+       }
+
+       physmap_idx += 2;
+       *physmap_idxp = physmap_idx;
+       if (physmap_idx == PHYSMAP_SIZE) {
+               printf(
+               "Too many segments in the physical address map, giving up\n");
+               return (0);
+       }
+
+       /*
+        * Move the last 'N' entries down to make room for the new
+        * entry if needed.
+        */
+       for (i = physmap_idx; i > insert_idx; i -= 2) {
+               physmap[i] = physmap[i - 2];
+               physmap[i + 1] = physmap[i - 1];
+       }
+
+       /* Insert the new entry. */
+       physmap[insert_idx] = smap->base;
+       physmap[insert_idx + 1] = smap->base + smap->length;
+       return (1);
+}
+
 /*
  * Populate the (physmap) array with base/bound pairs describing the
  * available physical memory in the system, then test this memory and
@@ -1235,40 +1306,9 @@ getmemsize(caddr_t kmdp, u_int64_t first
        smapsize = *((u_int32_t *)smapbase - 1);
        smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize);
 
-       for (smap = smapbase; smap < smapend; smap++) {
-               if (boothowto & RB_VERBOSE)
-                       printf("SMAP type=%02x base=%016lx len=%016lx\n",
-                           smap->type, smap->base, smap->length);
-
-               if (smap->type != SMAP_TYPE_MEMORY)
-                       continue;
-
-               if (smap->length == 0)
-                       continue;
-
-               for (i = 0; i <= physmap_idx; i += 2) {
-                       if (smap->base < physmap[i + 1]) {
-                               if (boothowto & RB_VERBOSE)
-                                       printf(
-       "Overlapping or non-monotonic memory region, ignoring second region\n");
-                               continue;
-                       }
-               }
-
-               if (smap->base == physmap[physmap_idx + 1]) {
-                       physmap[physmap_idx + 1] += smap->length;
-                       continue;
-               }
-
-               physmap_idx += 2;
-               if (physmap_idx == PHYSMAP_SIZE) {
-                       printf(
-               "Too many segments in the physical address map, giving up\n");
+       for (smap = smapbase; smap < smapend; smap++)
+               if (!add_smap_entry(smap, physmap, &physmap_idx))
                        break;
-               }
-               physmap[physmap_idx] = smap->base;
-               physmap[physmap_idx + 1] = smap->base + smap->length;
-       }
 
        /*
         * Find the 'base memory' segment for SMP

Modified: stable/8/sys/i386/i386/machdep.c
==============================================================================
--- stable/8/sys/i386/i386/machdep.c    Fri Sep 25 14:58:30 2009        
(r197483)
+++ stable/8/sys/i386/i386/machdep.c    Fri Sep 25 15:08:26 2009        
(r197484)
@@ -1946,7 +1946,7 @@ sdtossd(sd, ssd)
 static int
 add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp)
 {
-       int i, physmap_idx;
+       int i, insert_idx, physmap_idx;
 
        physmap_idx = *physmap_idxp;
        
@@ -1968,17 +1968,34 @@ add_smap_entry(struct bios_smap *smap, v
        }
 #endif
 
+       /*
+        * Find insertion point while checking for overlap.  Start off by
+        * assuming the new entry will be added to the end.
+        */
+       insert_idx = physmap_idx + 2;
        for (i = 0; i <= physmap_idx; i += 2) {
                if (smap->base < physmap[i + 1]) {
+                       if (smap->base + smap->length <= physmap[i]) {
+                               insert_idx = i;
+                               break;
+                       }
                        if (boothowto & RB_VERBOSE)
                                printf(
-       "Overlapping or non-monotonic memory region, ignoring second region\n");
+                   "Overlapping memory regions, ignoring second region\n");
                        return (1);
                }
        }
 
-       if (smap->base == physmap[physmap_idx + 1]) {
-               physmap[physmap_idx + 1] += smap->length;
+       /* See if we can prepend to the next entry. */
+       if (insert_idx <= physmap_idx &&
+           smap->base + smap->length == physmap[insert_idx]) {
+               physmap[insert_idx] = smap->base;
+               return (1);
+       }
+
+       /* See if we can append to the previous entry. */
+       if (insert_idx > 0 && smap->base == physmap[insert_idx - 1]) {
+               physmap[insert_idx - 1] += smap->length;
                return (1);
        }
 
@@ -1989,8 +2006,19 @@ add_smap_entry(struct bios_smap *smap, v
                "Too many segments in the physical address map, giving up\n");
                return (0);
        }
-       physmap[physmap_idx] = smap->base;
-       physmap[physmap_idx + 1] = smap->base + smap->length;
+
+       /*
+        * Move the last 'N' entries down to make room for the new
+        * entry if needed.
+        */
+       for (i = physmap_idx; i > insert_idx; i -= 2) {
+               physmap[i] = physmap[i - 2];
+               physmap[i + 1] = physmap[i - 1];
+       }
+
+       /* Insert the new entry. */
+       physmap[insert_idx] = smap->base;
+       physmap[insert_idx + 1] = smap->base + smap->length;
        return (1);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to