Skip to content

Commit

Permalink
[SPARC64]: Fix "mem=xxx" handling.
Browse files Browse the repository at this point in the history
We were not being careful enough.  When we trim the physical
memory areas, we have to make sure we don't remove the kernel
image or initial ramdisk image ranges.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Dec 31, 2006
1 parent bfff6e9 commit 6fc5bae
Showing 1 changed file with 124 additions and 23 deletions.
147 changes: 124 additions & 23 deletions arch/sparc64/mm/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,115 @@ static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn,
prom_halt();
}

static void __init trim_pavail(unsigned long *cur_size_p,
unsigned long *end_of_phys_p)
{
unsigned long to_trim = *cur_size_p - cmdline_memory_size;
unsigned long avoid_start, avoid_end;
int i;

to_trim = PAGE_ALIGN(to_trim);

avoid_start = avoid_end = 0;
#ifdef CONFIG_BLK_DEV_INITRD
avoid_start = initrd_start;
avoid_end = PAGE_ALIGN(initrd_end);
#endif

/* Trim some pavail[] entries in order to satisfy the
* requested "mem=xxx" kernel command line specification.
*
* We must not trim off the kernel image area nor the
* initial ramdisk range (if any). Also, we must not trim
* any pavail[] entry down to zero in order to preserve
* the invariant that all pavail[] entries have a non-zero
* size which is assumed by all of the code in here.
*/
for (i = 0; i < pavail_ents; i++) {
unsigned long start, end, kern_end;
unsigned long trim_low, trim_high, n;

kern_end = PAGE_ALIGN(kern_base + kern_size);

trim_low = start = pavail[i].phys_addr;
trim_high = end = start + pavail[i].reg_size;

if (kern_base >= start &&
kern_base < end) {
trim_low = kern_base;
if (kern_end >= end)
continue;
}
if (kern_end >= start &&
kern_end < end) {
trim_high = kern_end;
}
if (avoid_start &&
avoid_start >= start &&
avoid_start < end) {
if (trim_low > avoid_start)
trim_low = avoid_start;
if (avoid_end >= end)
continue;
}
if (avoid_end &&
avoid_end >= start &&
avoid_end < end) {
if (trim_high < avoid_end)
trim_high = avoid_end;
}

if (trim_high <= trim_low)
continue;

if (trim_low == start && trim_high == end) {
/* Whole chunk is available for trimming.
* Trim all except one page, in order to keep
* entry non-empty.
*/
n = (end - start) - PAGE_SIZE;
if (n > to_trim)
n = to_trim;

if (n) {
pavail[i].phys_addr += n;
pavail[i].reg_size -= n;
to_trim -= n;
}
} else {
n = (trim_low - start);
if (n > to_trim)
n = to_trim;

if (n) {
pavail[i].phys_addr += n;
pavail[i].reg_size -= n;
to_trim -= n;
}
if (to_trim) {
n = end - trim_high;
if (n > to_trim)
n = to_trim;
if (n) {
pavail[i].reg_size -= n;
to_trim -= n;
}
}
}

if (!to_trim)
break;
}

/* Recalculate. */
*cur_size_p = 0UL;
for (i = 0; i < pavail_ents; i++) {
*end_of_phys_p = pavail[i].phys_addr +
pavail[i].reg_size;
*cur_size_p += pavail[i].reg_size;
}
}

static unsigned long __init bootmem_init(unsigned long *pages_avail,
unsigned long phys_base)
{
Expand All @@ -889,31 +998,13 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
end_of_phys_memory = pavail[i].phys_addr +
pavail[i].reg_size;
bytes_avail += pavail[i].reg_size;
if (cmdline_memory_size) {
if (bytes_avail > cmdline_memory_size) {
unsigned long slack = bytes_avail - cmdline_memory_size;

bytes_avail -= slack;
end_of_phys_memory -= slack;

pavail[i].reg_size -= slack;
if ((long)pavail[i].reg_size <= 0L) {
pavail[i].phys_addr = 0xdeadbeefUL;
pavail[i].reg_size = 0UL;
pavail_ents = i;
} else {
pavail[i+1].reg_size = 0Ul;
pavail[i+1].phys_addr = 0xdeadbeefUL;
pavail_ents = i + 1;
}
break;
}
}
}

*pages_avail = bytes_avail >> PAGE_SHIFT;

end_pfn = end_of_phys_memory >> PAGE_SHIFT;
/* Determine the location of the initial ramdisk before trying
* to honor the "mem=xxx" command line argument. We must know
* where the kernel image and the ramdisk image are so that we
* do not trim those two areas from the physical memory map.
*/

#ifdef CONFIG_BLK_DEV_INITRD
/* Now have to check initial ramdisk, so that bootmap does not overwrite it */
Expand All @@ -932,6 +1023,16 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
}
}
#endif

if (cmdline_memory_size &&
bytes_avail > cmdline_memory_size)
trim_pavail(&bytes_avail,
&end_of_phys_memory);

*pages_avail = bytes_avail >> PAGE_SHIFT;

end_pfn = end_of_phys_memory >> PAGE_SHIFT;

/* Initialize the boot-time allocator. */
max_pfn = max_low_pfn = end_pfn;
min_low_pfn = (phys_base >> PAGE_SHIFT);
Expand Down

0 comments on commit 6fc5bae

Please sign in to comment.