From: Michael Frank Enclosed is a patch for x86 to make highmem= option easier to use. - Automates alignment of highmem zone - Fixes invalid highmem settings whether too small or to large - Adds entry in kernel-parameters.txt - Permits highmem emulation, so people with less than 896MB of memory can test CONFIG_HIGHMEM. Highmem emulation can be used on any machine with at least 72MB RAM. The patch does not add to bloat as it is part of __init code. --- Documentation/kernel-parameters.txt | 8 +++ arch/i386/kernel/setup.c | 91 +++++++++++++++++++++++++++--------- 2 files changed, 77 insertions(+), 22 deletions(-) diff -puN arch/i386/kernel/setup.c~highmem-equals-user-friendliness arch/i386/kernel/setup.c --- 25/arch/i386/kernel/setup.c~highmem-equals-user-friendliness 2004-02-09 00:14:08.000000000 -0800 +++ 25-akpm/arch/i386/kernel/setup.c 2004-02-09 00:14:08.000000000 -0800 @@ -588,9 +588,12 @@ static void __init parse_cmdline_early ( #endif /* CONFIG_ACPI_BOOT */ /* - * highmem=size forces highmem to be exactly 'size' bytes. + * highmem=size forces highmem to be at most 'size' bytes. * This works even on boxes that have no highmem otherwise. * This also works to reduce highmem size on bigger boxes. + * + * Note: highmem sise is adjusted downward for proper zone + * alignment of the highmem physical start address. */ if (c == ' ' && !memcmp(from, "highmem=", 8)) highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT; @@ -657,6 +660,11 @@ void __init find_max_pfn(void) /* * Determine low and high memory ranges: */ + +#define ZONE_REQUIRED_PAGE_ALIGNMENT (1UL << (MAX_ORDER-1)) +#define ZONE_REQUIRED_PAGE_ALIGNMENT_MASK (ZONE_REQUIRED_PAGE_ALIGNMENT-1) +#define PAGES_FOR_64MB (64*1024*1024/PAGE_SIZE) + unsigned long __init find_max_low_pfn(void) { unsigned long max_low_pfn; @@ -668,14 +676,16 @@ unsigned long __init find_max_low_pfn(vo if (highmem_pages + MAXMEM_PFN < max_pfn) max_pfn = MAXMEM_PFN + highmem_pages; if (highmem_pages + MAXMEM_PFN > max_pfn) { - printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages)); - highmem_pages = 0; + printk("Warning reducing highmem=%uMB to: %luMB.\n", + pages_to_mb(highmem_pages), + pages_to_mb((max_pfn - MAXMEM_PFN))); + highmem_pages = max_pfn - MAXMEM_PFN; } max_low_pfn = MAXMEM_PFN; #ifndef CONFIG_HIGHMEM /* Maximum memory usable is what is directly addressable */ - printk(KERN_WARNING "Warning only %ldMB will be used.\n", - MAXMEM>>20); + printk(KERN_WARNING "Warning only %luMB will be used.\n", + MAXMEM >> 20); if (max_pfn > MAX_NONPAE_PFN) printk(KERN_WARNING "Use a PAE enabled kernel.\n"); else @@ -690,26 +700,63 @@ unsigned long __init find_max_low_pfn(vo } #endif /* !CONFIG_X86_PAE */ #endif /* !CONFIG_HIGHMEM */ - } else { - if (highmem_pages == -1) - highmem_pages = 0; + } else if (highmem_pages == -1) + highmem_pages = 0; #ifdef CONFIG_HIGHMEM - if (highmem_pages >= max_pfn) { - printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn)); - highmem_pages = 0; - } - if (highmem_pages) { - if (max_low_pfn-highmem_pages < 64*1024*1024/PAGE_SIZE){ - printk(KERN_ERR "highmem size %uMB results in smaller than 64MB lowmem, ignoring it.\n", pages_to_mb(highmem_pages)); - highmem_pages = 0; - } - max_low_pfn -= highmem_pages; - } + if (!highmem_pages) + goto out; + if (max_pfn < PAGES_FOR_64MB + ZONE_REQUIRED_PAGE_ALIGNMENT * 2) { + printk(KERN_ERR "Error highmem support requires at least %luMB " + "but only %luMB are available.\n", + pages_to_mb(PAGES_FOR_64MB + + ZONE_REQUIRED_PAGE_ALIGNMENT * 2), + pages_to_mb(max_pfn)); + highmem_pages = 0; + goto out; + } + if (highmem_pages > max_pfn) { + printk(KERN_WARNING "Warning highmem=%uMB is bigger than " + "available %luMB and will be adjusted.\n", + pages_to_mb(highmem_pages), pages_to_mb(max_pfn)); + } + if (highmem_pages <= ZONE_REQUIRED_PAGE_ALIGNMENT) { + printk(KERN_WARNING "Warning highmem=%uMB is too small and has " + "been adjusted to: %luMB.\n", + pages_to_mb(highmem_pages), + pages_to_mb(ZONE_REQUIRED_PAGE_ALIGNMENT * 2)); + highmem_pages = ZONE_REQUIRED_PAGE_ALIGNMENT * 2; + } + if (max_low_pfn < highmem_pages || + max_low_pfn-highmem_pages < PAGES_FOR_64MB){ + highmem_pages = max_low_pfn - PAGES_FOR_64MB; + printk(KERN_WARNING "Warning highmem size adjusted for a " + "minimum of 64MB lowmem to: %uMB.\n", + pages_to_mb(highmem_pages)); + } + max_low_pfn -= highmem_pages; + + if (max_low_pfn & ZONE_REQUIRED_PAGE_ALIGNMENT_MASK) { + printk(KERN_WARNING "Warning bad highmem zone alignment 0x%lx, " + "highmem size will be adjusted.\n", + (max_low_pfn & ZONE_REQUIRED_PAGE_ALIGNMENT_MASK) << + PAGE_SHIFT); + highmem_pages -= ZONE_REQUIRED_PAGE_ALIGNMENT - + (max_low_pfn & ZONE_REQUIRED_PAGE_ALIGNMENT_MASK); + max_low_pfn &= ~ZONE_REQUIRED_PAGE_ALIGNMENT_MASK; + max_low_pfn += ZONE_REQUIRED_PAGE_ALIGNMENT; + printk(KERN_WARNING "Warning lowmem size adjusted for zone " + "alignment to: %luMB.\n", + pages_to_mb(max_low_pfn)); + printk(KERN_WARNING "Warning highmem size adjusted for zone " + "alignment to: %uMB.\n", + pages_to_mb(highmem_pages)); + } +out: #else - if (highmem_pages) - printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n"); + if (highmem_pages) + printk(KERN_ERR "ignoring highmem size on non-highmem " + "kernel!\n"); #endif - } return max_low_pfn; } diff -puN Documentation/kernel-parameters.txt~highmem-equals-user-friendliness Documentation/kernel-parameters.txt --- 25/Documentation/kernel-parameters.txt~highmem-equals-user-friendliness 2004-02-09 00:14:08.000000000 -0800 +++ 25-akpm/Documentation/kernel-parameters.txt 2004-02-09 00:14:08.000000000 -0800 @@ -394,6 +394,14 @@ running once the system is up. hd?= [HW] (E)IDE subsystem hd?lun= See Documentation/ide.txt. + highmem=size[KMG] [IA32,KNL,BOOT] forces highmem to be at most 'size' bytes. + This works even on boxes with at least 72MB RAM that have no + highmem otherwise. This also works to reduce highmem size on + bigger boxes. + + Note: highmem is adjusted downward for proper zone alignment + of the highmem physical start address + hisax= [HW,ISDN] See Documentation/isdn/README.HiSax. _