| Summary: | [amd64] [patch] FreeBSD/amd64 can't see all system memory | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | James R. Van Artsdalen <james-freebsd-current> | ||||
| Component: | amd64 | Assignee: | freebsd-amd64 (Nobody) <amd64> | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | ||||||
| Priority: | Normal | ||||||
| Version: | 9.0-CURRENT | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
|
Description
James R. Van Artsdalen
2009-08-27 00:00:08 UTC
Can you try this alternate patch instead? I am leery of manipulating the SMAP
directly since it resides in the kernel's module metadata which in theory
should be read-only. This patch changes the SMAP code to do an insertion sort
into the physmap[] array for each new entry that is added. I also changed the
amd64 code to use a separate static routine to add each entry similar to i386
which fixes the bug with overlapping regions that you noted while keeping the
SMAP code identical between the two archs.
--- //depot/vendor/freebsd/src/sys/amd64/amd64/machdep.c 2009/08/20 23:00:20
+++ //depot/user/jhb/numa/sys/amd64/amd64/machdep.c 2009/09/14 19:37:10
@@ -1192,6 +1192,77 @@
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 or non-monotonic memory region, 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 - 2; 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 @@
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
--- //depot/vendor/freebsd/src/sys/i386/i386/machdep.c 2009/09/04 14:55:14
+++ //depot/user/jhb/numa/sys/i386/i386/machdep.c 2009/09/14 19:37:10
@@ -1946,7 +1946,7 @@
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,8 +1968,17 @@
}
#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");
@@ -1977,8 +1986,16 @@
}
}
- 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 @@
"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 - 2; 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);
}
--
John Baldwin
Author: jhb Date: Tue Sep 22 16:51:00 2009 New Revision: 197410 URL: http://svn.freebsd.org/changeset/base/197410 Log: - 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. PR: amd64/138220 Reported by: James R. Van Artsdalen james of jrv org MFC after: 3 days Modified: head/sys/amd64/amd64/machdep.c head/sys/i386/i386/machdep.c Modified: head/sys/amd64/amd64/machdep.c ============================================================================== --- head/sys/amd64/amd64/machdep.c Tue Sep 22 16:28:07 2009 (r197409) +++ head/sys/amd64/amd64/machdep.c Tue Sep 22 16:51:00 2009 (r197410) @@ -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: head/sys/i386/i386/machdep.c ============================================================================== --- head/sys/i386/i386/machdep.c Tue Sep 22 16:28:07 2009 (r197409) +++ head/sys/i386/i386/machdep.c Tue Sep 22 16:51:00 2009 (r197410) @@ -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-unsubscribe@freebsd.org" State Changed From-To: open->closed Fixed in HEAD, 8, and 7. |