Linux 2.0.36 patch for 2GB Physical Memory

Leonard N. Zubkoff (lnz@varesearch.com)
Thu, 3 Dec 1998 14:00:31 -0800


I have created a patch for Linux 2.0.36 that allows up to 2GB of physical
memory to be utilized since we have customers that need this much or even more
physical memory. In order to allow this expansion, the size of the virtual
address space available to each process is reduced to 2GB - 64MB. That in and
of itself should not be a serious limitation, but it does change the layout of
the virtual address space somewhat.

With an unmodified Linux 2.0.36 kernel, each process is allowed approximately
1GB for its private text and data space growing upward from the bottom, with
the remaining 2GB being used by libraries and other mmap'ed data growing upward
from TASK_SIZE/3 and the stack growing downward from the top. Reducing the
process total virtual address space (TASK_SIZE) from 3GB to 2GB lowers the
point where mmap'ed data is allocated, preserving the relative sizes of these
three memory regions. However, with 2GB physical memory it is entirely
possible that some applications might wish to use as much memory as possible
for process private data, whereas others might wish to use the largest shared
memory regions possible. Therefore, the point where mmap'ed data starts is
made configurable by this patch, with the default being TASK_SIZE/3.

To change the default point where mmap'ed data and libraries are initially
allocated, one need merely set an explicit RLIMIT_DATA using a system call or a
shell's builtin limit commands.

Leonard

--- linux/arch/i386/mm/init.c- Tue Aug 12 13:06:54 1997
+++ linux/arch/i386/mm/init.c Wed Nov 4 09:57:21 1998
@@ -176,23 +176,25 @@
: : :"ax");
#endif
wp_works_ok = 1;
- pgd_val(pg_dir[0]) = _PAGE_TABLE | _PAGE_4M | address;
- pgd_val(pg_dir[768]) = _PAGE_TABLE | _PAGE_4M | address;
+ if (address < 0x7C000000)
+ pgd_val(pg_dir[0]) = _PAGE_TABLE | _PAGE_4M | address;
+ pgd_val(pg_dir[496]) = _PAGE_TABLE | _PAGE_4M | address;
pg_dir++;
address += 4*1024*1024;
continue;
}
#endif
- /* map the memory at virtual addr 0xC0000000 */
- pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[768]));
+ /* map the memory at virtual addr 0x7C000000 */
+ pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[496]));
if (!pg_table) {
pg_table = (pte_t *) start_mem;
start_mem += PAGE_SIZE;
}

/* also map it temporarily at 0x0000000 for init */
- pgd_val(pg_dir[0]) = _PAGE_TABLE | (unsigned long) pg_table;
- pgd_val(pg_dir[768]) = _PAGE_TABLE | (unsigned long) pg_table;
+ if (address < 0x7C000000)
+ pgd_val(pg_dir[0]) = _PAGE_TABLE | (unsigned long) pg_table;
+ pgd_val(pg_dir[496]) = _PAGE_TABLE | (unsigned long) pg_table;
pg_dir++;
for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
if (address < end_mem)
--- linux/arch/i386/kernel/process.c- Wed Jun 3 15:17:46 1998
+++ linux/arch/i386/kernel/process.c Wed Nov 4 09:57:21 1998
@@ -314,10 +314,10 @@

/* Remap the kernel at virtual address zero, as well as offset zero
from the kernel segment. This assumes the kernel segment starts at
- virtual address 0xc0000000. */
+ virtual address 0x7C000000. */

- memcpy (swapper_pg_dir, swapper_pg_dir + 768,
- sizeof (swapper_pg_dir [0]) * 256);
+ memcpy (swapper_pg_dir, swapper_pg_dir + 496,
+ sizeof (swapper_pg_dir [0]) * 528);

/* Make sure the first page is mapped to the start of physical memory.
It is normally not mapped, to trap kernel NULL pointer dereferences. */
--- linux/arch/i386/kernel/setup.c- Wed Nov 4 09:43:11 1998
+++ linux/arch/i386/kernel/setup.c Wed Nov 4 09:57:48 1998
@@ -155,6 +155,8 @@
else
printk("Memory: sized by int13 088h\n");
#endif
+ if (memory_end > (unsigned long) 2048*1024*1024)
+ memory_end = (unsigned long) 2048*1024*1024;
memory_end &= PAGE_MASK;
#ifdef CONFIG_BLK_DEV_RAM
rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
@@ -165,17 +167,6 @@
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
#endif
-
- /*
- * The 1Gig sanity checker.
- */
-
- if (memory_end > 980*1024*1024)
- {
- printk(KERN_WARNING "Warning only 980Mb will be used.\n");
- memory_end = 980 * 1024 * 1024;
- }
-
if (!MOUNT_ROOT_RDONLY)
root_mountflags &= ~MS_RDONLY;
memory_start = (unsigned long) &_end;
--- linux/arch/i386/kernel/head.S- Wed Nov 4 09:43:11 1998
+++ linux/arch/i386/kernel/head.S Wed Nov 4 10:08:41 1998
@@ -329,7 +329,7 @@
* sets up a idt with 256 entries pointing to
* ignore_int, interrupt gates. It doesn't actually load
* idt - that can be done only after paging has been enabled
- * and the kernel moved to 0xC0000000. Interrupts
+ * and the kernel moved to 0x7C000000. Interrupts
* are enabled elsewhere, when we can be relatively
* sure everything is ok.
*/
@@ -370,9 +370,9 @@
/* Identity-map the kernel in low 4MB memory for ease of transition */
/* set present bit/user r/w */
movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)
-/* But the real place is at 0xC0000000 */
+/* But the real place is at 0x7C000000 */
/* set present bit/user r/w */
- movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)+3072
+ movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)+1984
movl $ SYMBOL_NAME(pg0)+4092,%edi
movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */
std
@@ -460,7 +460,7 @@
.word 0
idt_descr:
.word 256*8-1 # idt contains 256 entries
- .long 0xc0000000+SYMBOL_NAME(idt)
+ .long 0x7C000000+SYMBOL_NAME(idt)

ALIGN
.word 0
@@ -470,19 +470,19 @@
#else
.word (8+2*NR_TASKS)*8-1
#endif
- .long 0xc0000000+SYMBOL_NAME(gdt)
+ .long 0x7C000000+SYMBOL_NAME(gdt)

/*
- * This gdt setup gives the kernel a 1GB address space at virtual
- * address 0xC0000000 - space enough for expansion, I hope.
+ * This gdt setup gives the kernel a 2GB+64MB address space at virtual
+ * address 0x7C000000 - space enough for expansion, I hope.
*/
ENTRY(gdt)
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0000000000000000 /* not used */
- .quad 0xc0c39a000000ffff /* 0x10 kernel 1GB code at 0xC0000000 */
- .quad 0xc0c392000000ffff /* 0x18 kernel 1GB data at 0xC0000000 */
- .quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */
- .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */
+ .quad 0x7cc89a0000003fff /* 0x10 kernel 2GB+64MB code at 0x7C000000 */
+ .quad 0x7cc8920000003fff /* 0x18 kernel 2GB+64MB data at 0x7C000000 */
+ .quad 0x00c7fa000000cfff /* 0x23 user 2GB-64MB code at 0x00000000 */
+ .quad 0x00c7f2000000cfff /* 0x2b user 2GB-64MB data at 0x00000000 */
.quad 0x0000000000000000 /* not used */
.quad 0x0000000000000000 /* not used */
.fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */
--- linux/mm/mmap.c- Wed Nov 4 09:43:12 1998
+++ linux/mm/mmap.c Thu Nov 5 15:54:28 1998
@@ -311,8 +311,11 @@

if (len > MAX_USER_ADDR)
return 0;
- if (!addr)
- addr = MMAP_SEARCH_START;
+ if (!addr) {
+ addr = current->rlim[RLIMIT_DATA].rlim_cur;
+ if (addr >= RLIM_INFINITY)
+ addr = MMAP_SEARCH_START;
+ }
addr = PAGE_ALIGN(addr);

for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
--- linux/drivers/char/apm_bios.c- Wed Nov 4 09:43:11 1998
+++ linux/drivers/char/apm_bios.c Wed Nov 4 10:00:08 1998
@@ -1167,11 +1167,11 @@
apm_bios_entry.offset = apm_bios_info.offset;
apm_bios_entry.segment = APM_CS;
set_base(gdt[APM_CS >> 3],
- 0xc0000000 + ((unsigned long)apm_bios_info.cseg << 4));
+ 0x7C000000 + ((unsigned long)apm_bios_info.cseg << 4));
set_base(gdt[APM_CS_16 >> 3],
- 0xc0000000 + ((unsigned long)apm_bios_info.cseg_16 << 4));
+ 0x7C000000 + ((unsigned long)apm_bios_info.cseg_16 << 4));
set_base(gdt[APM_DS >> 3],
- 0xc0000000 + ((unsigned long)apm_bios_info.dseg << 4));
+ 0x7C000000 + ((unsigned long)apm_bios_info.dseg << 4));
if (apm_bios_info.version == 0x100) {
set_limit(gdt[APM_CS >> 3], 64 * 1024);
set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
--- linux/include/asm-i386/processor.h- Wed Nov 4 09:43:12 1998
+++ linux/include/asm-i386/processor.h Thu Nov 5 15:55:48 1998
@@ -83,10 +83,10 @@
#define MCA_bus__is_a_macro /* for versions in ksyms.c */

/*
- * User space process size: 3GB. This is hardcoded into a few places,
+ * User space process size: 2GB-64MB. This is hardcoded into a few places,
* so don't change it unless you know what you are doing.
*/
-#define TASK_SIZE (0xC0000000UL)
+#define TASK_SIZE (0x7C000000UL)
#define MAX_USER_ADDR TASK_SIZE
#define MMAP_SEARCH_START (TASK_SIZE/3)

@@ -162,7 +162,7 @@
unsigned long v86flags, v86mask, v86mode;
};

-#define INIT_MMAP { &init_mm, 0, 0x40000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
+#define INIT_MMAP { &init_mm, 0, 0x84000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }

#define INIT_TSS { \
0,0, \
--- linux/include/asm-i386/pgtable.h- Wed Nov 4 09:43:44 1998
+++ linux/include/asm-i386/pgtable.h Wed Nov 4 09:57:21 1998
@@ -46,13 +46,13 @@
* NOTE! The intel "invlpg" semantics are extremely strange. The
* chip will add the segment base to the memory address, even though
* no segment checking is done. We correct for this by using an
- * offset of 0x40000000 that will wrap around the kernel segment base
- * of 0xC0000000 to get the correct address (it will always be outside
+ * offset of 0x84000000 that will wrap around the kernel segment base
+ * of 0x7C000000 to get the correct address (it will always be outside
* the kernel segment, but we're only interested in the final linear
* address.
*/
#define __invlpg_mem(addr) \
- (((char *)(addr))[0x40000000])
+ (((char *)(addr))[0x84000000])
#define __invlpg(addr) \
__asm__ __volatile__("invlpg %0": :"m" (__invlpg_mem(addr)))

--- linux/include/asm-i386/system.h- Wed Nov 4 09:43:12 1998
+++ linux/include/asm-i386/system.h Wed Nov 4 09:57:21 1998
@@ -275,7 +275,7 @@
"movb %%ah,%6\n\t" \
"rorl $16,%%eax" \
: /* no output */ \
- :"a" (addr+0xc0000000), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
+ :"a" (addr+0x7C000000), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
"m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
)

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/