Patch from David Hansen, originally by Ingo, with a few touches from Christoph Hellwig. It makes the ia32 kernel/user memory split configurable. "Whether they're a user that is doing a scientific application that needs more than 3GB, or a large PAE machine that needs more ZONE_NORMAL, lots of people are applying patches to change PAGE_OFFSET. This patch lets you do it in a config option. It is a port from Andrea's 2.4 tree, and I believe that Ingo is the original author." arch/i386/Kconfig | 42 ++++++++++++++++++++++++++++++++++++++++++ arch/i386/Makefile | 1 + arch/i386/vmlinux.lds.S | 2 +- include/asm-i386/page.h | 25 +++++++++++++++++++++++-- include/asm-i386/processor.h | 4 ++++ mm/memory.c | 20 ++++++++++++++++---- 6 files changed, 87 insertions(+), 7 deletions(-) diff -puN arch/i386/Kconfig~config-PAGE_OFFSET arch/i386/Kconfig --- 25/arch/i386/Kconfig~config-PAGE_OFFSET 2003-05-04 23:39:57.000000000 -0700 +++ 25-akpm/arch/i386/Kconfig 2003-05-04 23:40:04.000000000 -0700 @@ -666,6 +666,48 @@ config HIGHMEM64G endchoice +choice + help + On i386, a process can only virtually address 4GB of memory. This + lets you select how much of that virtual space you would like to + devoted to userspace, and how much to the kernel. + + Some userspace programs would like to address as much as possible and + have few demands of the kernel other than it get out of the way. These + users may opt to use the 3.5GB option to give their userspace program + as much room as possible. Due to alignment issues imposed by PAE, + the "3.5GB" option is unavailable if "64GB" high memory support is + enabled. + + Other users (especially those who use PAE) may be running out of + ZONE_NORMAL memory. Those users may benefit from increasing the + kernel's virtual address space size by taking it away from userspace, + which may not need all of its space. An indicator that this is + happening is when /proc/Meminfo's "LowFree:" is a small percentage of + "LowTotal:" while "HighFree:" is very large. + + If unsure, say "3GB" + prompt "User address space size" + default 1GB + +config 025GB + bool "3.75 GB" + depends on !HIGHMEM64G + +config 05GB + bool "3.5 GB" + depends on !HIGHMEM64G + +config 1GB + bool "3 GB" + +config 2GB + bool "2 GB" + +config 3GB + bool "1 GB" +endchoice + config HIGHMEM bool depends on HIGHMEM64G || HIGHMEM4G diff -puN arch/i386/Makefile~config-PAGE_OFFSET arch/i386/Makefile --- 25/arch/i386/Makefile~config-PAGE_OFFSET 2003-05-04 23:39:57.000000000 -0700 +++ 25-akpm/arch/i386/Makefile 2003-05-04 23:39:57.000000000 -0700 @@ -97,6 +97,7 @@ drivers-$(CONFIG_OPROFILE) += arch/i386 CFLAGS += $(mflags-y) AFLAGS += $(mflags-y) +AFLAGS_vmlinux.lds.o += -imacros $(TOPDIR)/include/asm-i386/page.h boot := arch/i386/boot diff -puN arch/i386/vmlinux.lds.S~config-PAGE_OFFSET arch/i386/vmlinux.lds.S --- 25/arch/i386/vmlinux.lds.S~config-PAGE_OFFSET 2003-05-04 23:39:57.000000000 -0700 +++ 25-akpm/arch/i386/vmlinux.lds.S 2003-05-04 23:39:57.000000000 -0700 @@ -10,7 +10,7 @@ ENTRY(startup_32) jiffies = jiffies_64; SECTIONS { - . = 0xC0000000 + 0x100000; + . = __PAGE_OFFSET + 0x100000; /* read-only */ _text = .; /* Text and read-only data */ .text : { diff -puN include/asm-i386/page.h~config-PAGE_OFFSET include/asm-i386/page.h --- 25/include/asm-i386/page.h~config-PAGE_OFFSET 2003-05-04 23:39:57.000000000 -0700 +++ 25-akpm/include/asm-i386/page.h 2003-05-04 23:40:05.000000000 -0700 @@ -115,9 +115,30 @@ static __inline__ int get_order(unsigned #endif /* __ASSEMBLY__ */ #ifdef __ASSEMBLY__ -#define __PAGE_OFFSET (0xC0000000) +#include +#ifdef CONFIG_025GB +#define __PAGE_OFFSET (0xF0000000) +#elif defined(CONFIG_05GB) +#define __PAGE_OFFSET (0xE0000000) +#elif defined(CONFIG_1GB) +#define __PAGE_OFFSET (0xC0000000) +#elif defined(CONFIG_2GB) +#define __PAGE_OFFSET (0x80000000) +#elif defined(CONFIG_3GB) +#define __PAGE_OFFSET (0x40000000) +#endif #else -#define __PAGE_OFFSET (0xC0000000UL) +#ifdef CONFIG_025GB +#define __PAGE_OFFSET (0xF0000000UL) +#elif defined(CONFIG_05GB) +#define __PAGE_OFFSET (0xE0000000UL) +#elif defined(CONFIG_1GB) +#define __PAGE_OFFSET (0xC0000000UL) +#elif defined(CONFIG_2GB) +#define __PAGE_OFFSET (0x80000000UL) +#elif defined(CONFIG_3GB) +#define __PAGE_OFFSET (0x40000000UL) +#endif #endif diff -puN include/asm-i386/processor.h~config-PAGE_OFFSET include/asm-i386/processor.h --- 25/include/asm-i386/processor.h~config-PAGE_OFFSET 2003-05-04 23:39:57.000000000 -0700 +++ 25-akpm/include/asm-i386/processor.h 2003-05-04 23:39:57.000000000 -0700 @@ -288,7 +288,11 @@ extern unsigned int mca_pentium_flag; /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ +#ifdef CONFIG_05GB +#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 16)) +#else #define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) +#endif /* * Size of io_bitmap in longwords: 32 is ports 0-0x3ff. diff -puN mm/memory.c~config-PAGE_OFFSET mm/memory.c --- 25/mm/memory.c~config-PAGE_OFFSET 2003-05-04 23:39:57.000000000 -0700 +++ 25-akpm/mm/memory.c 2003-05-04 23:39:57.000000000 -0700 @@ -102,8 +102,7 @@ static inline void free_one_pmd(struct m static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir) { - int j; - pmd_t * pmd; + pmd_t * pmd, * md, * emd; if (pgd_none(*dir)) return; @@ -114,8 +113,21 @@ static inline void free_one_pgd(struct m } pmd = pmd_offset(dir, 0); pgd_clear(dir); - for (j = 0; j < PTRS_PER_PMD ; j++) - free_one_pmd(tlb, pmd+j); + /* + * Beware if changing the loop below. It once used int j, + * for (j = 0; j < PTRS_PER_PMD; j++) + * free_one_pmd(pmd+j); + * but some older i386 compilers (e.g. egcs-2.91.66, gcc-2.95.3) + * terminated the loop with a _signed_ address comparison + * using "jle", when configured for HIGHMEM64GB (X86_PAE). + * If also configured for 3GB of kernel virtual address space, + * if page at physical 0x3ffff000 virtual 0x7ffff000 is used as + * a pmd, when that mm exits the loop goes on to free "entries" + * found at 0x80000000 onwards. The loop below compiles instead + * to be terminated by unsigned address comparison using "jb". + */ + for (md = pmd, emd = pmd + PTRS_PER_PMD; md < emd; md++) + free_one_pmd(tlb,md); pmd_free_tlb(tlb, pmd); } _