diff -u --recursive --unidirectional-new-file linux-2.1.126/Documentation/Configure.help linux-2.1.126-bigphysarea/Documentation/Configure.help
--- linux-2.1.126/Documentation/Configure.help	Tue Oct 27 13:54:07 1998
+++ linux-2.1.126-bigphysarea/Documentation/Configure.help	Tue Oct 27 18:13:16 1998
@@ -154,6 +154,14 @@
   "real" root file system, etc. See Documentation/initrd.txt for
   details.
 
+Support for big physical area reservation
+CONFIG_BIGPHYS_AREA
+  Enables kernel support for reserving large areas of physical memory
+  at boot-time for use by certain device drivers (such as video 
+  framegrabbers, etc.) which require it. To use this feature, boot
+  the kernel with the boot-time option 'bigphysarea=nnn' where 
+  'nnn' is the number of pages (a page is usually 4K) to reserve.
+
 Loop device support
 CONFIG_BLK_DEV_LOOP
   Saying Y here will allow you to use a regular file as a block
diff -u --recursive --unidirectional-new-file linux-2.1.126/arch/alpha/config.in linux-2.1.126-bigphysarea/arch/alpha/config.in
--- linux-2.1.126/arch/alpha/config.in	Tue Oct 27 13:54:07 1998
+++ linux-2.1.126-bigphysarea/arch/alpha/config.in	Tue Oct 27 18:14:26 1998
@@ -175,6 +175,7 @@
 	define_bool CONFIG_ALPHA_AVANTI y
 fi
 
+
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'PCI quirks' CONFIG_PCI_QUIRKS
   if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -182,6 +183,7 @@
   fi
   bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
 fi
+bool 'Support for big physical area reservation' CONFIG_BIGPHYS_AREA
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
diff -u --recursive --unidirectional-new-file linux-2.1.126/arch/alpha/kernel/entry.S linux-2.1.126-bigphysarea/arch/alpha/kernel/entry.S
--- linux-2.1.126/arch/alpha/kernel/entry.S	Tue Oct 27 13:54:07 1998
+++ linux-2.1.126-bigphysarea/arch/alpha/kernel/entry.S	Fri Oct 30 16:40:22 1998
@@ -10,7 +10,7 @@
 #define rti	.long PAL_rti
 #define SIGCHLD	20
 
-#define NR_SYSCALLS 370
+#define NR_SYSCALLS 373
 #define osf_vfork sys_fork
 
 /*
@@ -1127,4 +1127,7 @@
 	.quad sys_getcwd
 	.quad sys_capget
 	.quad sys_capset
-	.quad sys_ni_syscall			/* 370 */
+	.quad sys_pmalloc			/* 370 */
+	.quad sys_pfree
+	.quad sys_memexec
+	.quad sys_ni_syscall			/* 373 */
diff -u --recursive --unidirectional-new-file linux-2.1.126/arch/alpha/kernel/process.c linux-2.1.126-bigphysarea/arch/alpha/kernel/process.c
--- linux-2.1.126/arch/alpha/kernel/process.c	Tue Oct 27 13:54:07 1998
+++ linux-2.1.126-bigphysarea/arch/alpha/kernel/process.c	Wed Nov  4 19:42:57 1998
@@ -409,3 +409,16 @@
 	unlock_kernel();
 	return error;
 }
+
+asmlinkage int sys_memexec(unsigned long a0, unsigned long a1, unsigned long a2,
+	unsigned long a3, unsigned long a4, unsigned long a5,
+	struct pt_regs regs)
+{
+	int error;
+
+	lock_kernel();
+	error = do_memexec( (caddr_t) a0, (caddr_t) a1, &regs);
+out:
+	unlock_kernel();
+	return error;
+}
diff -u --recursive --unidirectional-new-file linux-2.1.126/config.nodes linux-2.1.126-bigphysarea/config.nodes
--- linux-2.1.126/config.nodes	Thu Oct 29 08:28:33 1998
+++ linux-2.1.126-bigphysarea/config.nodes	Thu Nov  5 12:14:54 1998
@@ -50,6 +50,7 @@
 CONFIG_PCI_QUIRKS=y
 # CONFIG_PCI_OPTIMIZE is not set
 CONFIG_PCI_OLD_PROC=y
+CONFIG_BIGPHYS_AREA=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
diff -u --recursive --unidirectional-new-file linux-2.1.126/fs/exec.c linux-2.1.126-bigphysarea/fs/exec.c
--- linux-2.1.126/fs/exec.c	Tue Oct 27 13:54:12 1998
+++ linux-2.1.126-bigphysarea/fs/exec.c	Thu Nov  5 11:30:48 1998
@@ -54,6 +54,9 @@
 #include <linux/kmod.h>
 #endif
 
+#include <linux/module.h>
+#include <asm/io.h>
+
 asmlinkage int sys_exit(int exit_code);
 asmlinkage int sys_brk(unsigned long);
 
@@ -540,20 +543,24 @@
 
 	if (current->euid == current->uid && current->egid == current->gid)
 		current->dumpable = 1;
-	name = bprm->filename;
-	for (i=0; (ch = *(name++)) != '\0';) {
-		if (ch == '/')
-			i = 0;
-		else
-			if (i < 15)
-				current->comm[i++] = ch;
+
+	if( bprm ) {
+		name = bprm->filename;
+		for (i=0; (ch = *(name++)) != '\0';) {
+			if (ch == '/')
+				i = 0;
+			else
+				if (i < 15)
+					current->comm[i++] = ch;
+		}
+		current->comm[i] = '\0';
 	}
-	current->comm[i] = '\0';
 
 	flush_thread();
 
-	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
-	    permission(bprm->dentry->d_inode,MAY_READ))
+	if (bprm && (bprm->e_uid != current->euid
+		     || bprm->e_gid != current->egid
+		     || permission(bprm->dentry->d_inode,MAY_READ)))
 		current->dumpable = 0;
 
 	flush_old_signals(current);
@@ -876,4 +883,179 @@
 		free_page(bprm.page[i]);
 
 	return retval;
+}
+
+
+/*****************************************/
+
+/*
+ *  memexec() system call used to create a "new" process from
+ * a process image already in core.  This is used for the Computational
+ * Plant project at Sandia National Labs to start a job onto a diskless
+ * machine via a special loader daemon that receives the image over
+ * the network.
+ *
+ * Additionally, we assume that the layout of these segments are
+ * contiguous.  That is, the data begins as soon as the text ends.
+ *
+ * The segments are expected to be specified as:
+ *	Text	(Read-only)
+ *	Data	(Read-write)
+ *	BSS	(Read-write)	The heap starts at the bottom,
+ *				the stack starts at the top.
+ *				Since this is in support of our linear
+ *				memory project, we don't allow brk()
+ *				calls to extend the stack at all.
+ *
+ * The structure definition needs to be moved somewhere more
+ * public for other routines to be able to use it.
+ *
+ * Support for more exotic arrangements made upon request...
+ *
+ * Tramm Hudson <tbhudso@cs.sandia.gov>	
+ */
+
+struct memexec_segment {
+  caddr_t v_base, c_base, p_base;
+  size_t len;
+};
+
+asmlinkage int do_memexec(
+	struct memexec_segment *v_seglist, caddr_t entry,
+	struct pt_regs *regs )
+{
+	extern caddr_t v2p( struct task_struct *p, caddr_t v_base );
+	struct memexec_segment *seglist, *code, *data, *bss;
+	int i;
+
+	/* printk( "memexec: seglist=%p entry=%p\n", v_seglist, entry ); */
+
+	/* Find the real array of segments */
+	seglist = (struct memexec_segment*) v2p( current, (caddr_t) v_seglist );
+	if( !seglist ) {
+		printk( "memexec: seglist (%p) not valid for pid %d\n",
+		v_seglist, current->pid );
+		return -EINVAL;
+  	}
+
+  	/*
+	 * Find the physical location for each segment
+	 */
+  	for( i=0 ; i<3 ; i++ ) {
+		seglist[i].p_base = (
+			v2p( current, (caddr_t)seglist[i].v_base ) );
+
+		if( !seglist[i].p_base ) {
+			printk( "memexec: segment %d not valid: %p -> ?\n",
+				i, seglist[i].v_base );
+			return -EINVAL;
+		}
+
+		#ifdef DEBUG_MEMEXEC
+		{
+		  static char segs[][4] = { "TXT", "DAT", "BSS" };
+		  printk( "%s: %p -> %p\n\tMaps: 0x%p:0x%p (len 0x%lx)\n",
+			segs[i],
+			seglist[i].v_base,
+			seglist[i].p_base,
+			seglist[i].c_base,
+			seglist[i].c_base + seglist[i].len,
+			seglist[i].len );
+		}
+		#endif
+  	}
+
+  	code	= &seglist[0];
+  	data	= &seglist[1];
+  	bss	= &seglist[2];
+
+
+	/*
+	 *  This is copied straight from binfmt_aout.c
+	 */
+  	if( flush_old_exec( NULL ) )
+		return -1;
+
+	printk( "memexec: Flushed old binary\n" );
+
+	/* Ok, this is where we can't go back. */
+	current->personality = PER_LINUX;
+
+	/*
+	 *  I think these are the only structures that we need to fill
+	 * out here.  It wasn't clear what has to be done.  Since we've
+	 * just copied do_exec(), I think that we'll be ok...
+	 * 
+	 * Don't forget to decrement a small amount off the stack!
+	 */
+	current->mm->start_code =	(unsigned long) code->c_base;
+	current->mm->end_code =		(unsigned long) code->c_base+code->len;
+	current->mm->start_data =	(unsigned long) data->c_base;
+	current->mm->end_data =		(unsigned long) data->c_base+data->len;
+	current->mm->start_brk =	(unsigned long) bss->c_base;
+	current->mm->brk =		(unsigned long) bss->c_base+bss->len;
+	current->mm->start_stack =	(unsigned long) bss->c_base+bss->len - 0x10;
+
+	current->mm->rss = (unsigned long) code->len + data->len + bss->len;
+	current->mm->mmap = NULL;
+
+
+	/*
+	 *  Now that we've defined it, let's map the linear memory
+	 * to where the user may find it.
+	 */
+	for( i=0 ; i<3 ; i++ ) {
+	  printk( "mapping %d\n", i );
+	  if( !map_region( current,
+		(caddr_t)((unsigned long)seglist[i].p_base - IDENT_ADDR),
+		seglist[i].c_base,
+		seglist[i].len ) )
+			goto map_failed;
+	}
+
+	/* printk( "memexec: Mapped!\n" ); */
+
+
+	/*
+	 *  The rest of this is from binfmt_aout.c
+	 */
+	current->flags &= ~PF_FORKNOEXEC;
+
+	if( current->exec_domain && current->exec_domain->module )
+		__MOD_DEC_USE_COUNT( current->exec_domain->module );
+	if( current->binfmt && current->binfmt->module )
+		__MOD_DEC_USE_COUNT( current->binfmt->module );
+
+	current->exec_domain = NULL;
+	current->binfmt = NULL;
+
+	#ifdef DEBUG_MEMEXEC
+	{
+	  unsigned long *pc = v2p( current, code->c_base );
+	  int i;
+	  printk( "Just to check, the memory at the starting address:\n" );
+	  for( i=0 ; i<32 ; i+=2 )
+		printk( "%p: %016lx %016lx\n", pc+i, *(pc+i), *(pc+i+1) );
+
+	  printk( "\nGOT section:\n" );
+	  pc = v2p( current, (caddr_t) 0x000000012011f958 );
+	  for( i=0 ; i<32 ; i+=2 )
+		printk( "%p: %016lx %016lx\n", pc+i, *(pc+i), *(pc+i+1) );
+
+
+	  printk( "entry = %p -> %p\n", entry, v2p( current, entry ) );
+	}
+	  
+	printk( "memexec: Run that puppy!\n" );
+	#endif
+
+	start_thread( regs, entry, current->mm->start_stack );
+	if( current->flags & PF_PTRACED )
+		send_sig( SIGTRAP, current, 0 );
+
+	return 0;
+
+map_failed:
+	printk( "memexec failed! Unable to map regions\n" );
+	return -1;
 }
diff -u --recursive --unidirectional-new-file linux-2.1.126/fs/proc/array.c linux-2.1.126-bigphysarea/fs/proc/array.c
--- linux-2.1.126/fs/proc/array.c	Tue Oct 27 13:54:12 1998
+++ linux-2.1.126-bigphysarea/fs/proc/array.c	Tue Oct 27 18:16:02 1998
@@ -1230,6 +1230,8 @@
 extern int get_swaparea_info (char *);
 extern int get_hardware_list(char *);
 extern int get_stram_list(char *);
+extern int get_bigphysarea_info(char *);
+
 
 static long get_root_array(char * page, int type, char **start,
 	off_t offset, unsigned long length)
@@ -1322,6 +1324,11 @@
 		case PROC_STRAM:
 			return get_stram_list(page);
 #endif
+#ifdef CONFIG_BIGPHYS_AREA
+		case PROC_BIGPHYSAREA:
+			return get_bigphysarea_info(page);
+#endif
+
 	}
 	return -EBADF;
 }
diff -u --recursive --unidirectional-new-file linux-2.1.126/fs/proc/root.c linux-2.1.126-bigphysarea/fs/proc/root.c
--- linux-2.1.126/fs/proc/root.c	Sat Sep 19 14:44:48 1998
+++ linux-2.1.126-bigphysarea/fs/proc/root.c	Tue Oct 27 18:17:49 1998
@@ -606,6 +606,13 @@
 	0, &proc_array_inode_operations
 };
 #endif
+#ifdef CONFIG_BIGPHYS_AREA
+static struct proc_dir_entry proc_root_bigphysarea = {
+	PROC_BIGPHYSAREA, 11, "bigphysarea",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_array_inode_operations
+};
+#endif
 static struct proc_dir_entry proc_root_locks = {
 	PROC_LOCKS, 5, "locks",
 	S_IFREG | S_IRUGO, 1, 0, 0,
@@ -683,6 +690,10 @@
 #ifdef CONFIG_RTC
 	proc_register(&proc_root, &proc_root_rtc);
 #endif
+#ifdef CONFIG_BIGPHYS_AREA
+	proc_register(&proc_root, &proc_root_bigphysarea );
+#endif
+
 	proc_register(&proc_root, &proc_root_locks);
 
 	proc_register(&proc_root, &proc_root_mounts);
diff -u --recursive --unidirectional-new-file linux-2.1.126/include/asm-alpha/unistd.h linux-2.1.126-bigphysarea/include/asm-alpha/unistd.h
--- linux-2.1.126/include/asm-alpha/unistd.h	Tue Oct 27 13:57:48 1998
+++ linux-2.1.126-bigphysarea/include/asm-alpha/unistd.h	Mon Nov  2 10:31:25 1998
@@ -308,6 +308,10 @@
 #define __NR_capget			368
 #define __NR_capset			369
 
+#define __NR_pmalloc			370
+#define __NR_pfree			371
+#define __NR_memexec			372
+
 #if defined(__LIBRARY__) && defined(__GNUC__)
 
 #define _syscall_return(type)						\
diff -u --recursive --unidirectional-new-file linux-2.1.126/include/linux/bigphysarea.h linux-2.1.126-bigphysarea/include/linux/bigphysarea.h
--- linux-2.1.126/include/linux/bigphysarea.h	Wed Dec 31 17:00:00 1969
+++ linux-2.1.126-bigphysarea/include/linux/bigphysarea.h	Tue Oct 27 18:18:57 1998
@@ -0,0 +1,30 @@
+/* linux/mm/bigphysarea.h, M. Welsh (mdw@cs.cornell.edu)
+ * Copyright (c) 1996 by Matt Welsh.
+ *
+ * This is a set of routines which allow you to reserve a large (?) 
+ * amount of physical memory at boot-time, which can be allocated/deallocated
+ * by drivers. This memory is intended to be used for devices such as 
+ * video framegrabbers which need a lot of physical RAM (above the amount
+ * allocated by kmalloc). This is by no means efficient or recommended;
+ * to be used only in extreme circumstances.
+ *
+ */
+
+#ifndef __LINUX_BIGPHYSAREA_H 
+#define __LINUX_BIGPHYSAREA_H
+
+#include <linux/types.h>
+
+extern caddr_t bigphysarea;
+
+/* original interface */
+extern void bigphysarea_setup(char *str, int *ints);
+extern unsigned long bigphysarea_init(unsigned long mem_start, unsigned long mem_end);
+extern caddr_t bigphysarea_alloc(int size);
+extern void bigphysarea_free(caddr_t addr, int size);
+
+/* new interface */
+extern caddr_t bigphysarea_alloc_pages(int count, int align, int priority);
+extern void    bigphysarea_free_pages(caddr_t base);
+
+#endif __LINUX_BIGPHYSAREA_H
diff -u --recursive --unidirectional-new-file linux-2.1.126/include/linux/mm.h linux-2.1.126-bigphysarea/include/linux/mm.h
--- linux-2.1.126/include/linux/mm.h	Tue Oct 27 13:57:49 1998
+++ linux-2.1.126-bigphysarea/include/linux/mm.h	Tue Nov  3 14:48:49 1998
@@ -300,6 +300,8 @@
 extern unsigned long do_mmap(struct file *, unsigned long, unsigned long,
 	unsigned long, unsigned long, unsigned long);
 extern int do_munmap(unsigned long, size_t);
+extern caddr_t map_region( struct task_struct *tsk,
+	caddr_t p_base, caddr_t v_base, size_t len );
 
 /* filemap.c */
 extern void remove_inode_page(struct page *);
diff -u --recursive --unidirectional-new-file linux-2.1.126/include/linux/proc_fs.h linux-2.1.126-bigphysarea/include/linux/proc_fs.h
--- linux-2.1.126/include/linux/proc_fs.h	Tue Oct 27 13:57:49 1998
+++ linux-2.1.126-bigphysarea/include/linux/proc_fs.h	Tue Nov  3 14:57:27 1998
@@ -53,6 +53,7 @@
 	PROC_STRAM,
 	PROC_SOUND,
 	PROC_MTRR, /* whether enabled or not */
+	PROC_BIGPHYSAREA,
 	PROC_FS
 };
 
diff -u --recursive --unidirectional-new-file linux-2.1.126/init/main.c linux-2.1.126-bigphysarea/init/main.c
--- linux-2.1.126/init/main.c	Tue Oct 27 13:54:15 1998
+++ linux-2.1.126-bigphysarea/init/main.c	Thu Oct 29 07:23:09 1998
@@ -330,6 +330,10 @@
 extern void mdacon_setup(char *str, int *ints);
 #endif
 
+#ifdef CONFIG_BIGPHYS_AREA
+extern void bigphysarea_setup(char *str, int *ints);
+#endif
+
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
 #endif
@@ -840,6 +844,9 @@
 #ifdef CONFIG_MACMOUSE
 	{ "adb_buttons=", adb_mouse_setup },
 #endif
+#ifdef CONFIG_BIGPHYS_AREA
+	{ "bigphysarea=", bigphysarea_setup },
+#endif
 	{ 0, 0 }
 };
 
@@ -1143,6 +1150,11 @@
 		initrd_start = 0;
 	}
 #endif
+
+#ifdef CONFIG_BIGPHYS_AREA
+	memory_start = bigphysarea_init(memory_start,memory_end);
+#endif
+
 	mem_init(memory_start,memory_end);
 	kmem_cache_sizes_init();
 #ifdef CONFIG_PROC_FS
diff -u --recursive --unidirectional-new-file linux-2.1.126/kernel/ksyms.c linux-2.1.126-bigphysarea/kernel/ksyms.c
--- linux-2.1.126/kernel/ksyms.c	Tue Oct 27 13:54:15 1998
+++ linux-2.1.126-bigphysarea/kernel/ksyms.c	Thu Oct 29 07:25:04 1998
@@ -65,6 +65,10 @@
 #ifdef __SMP__
 #include <linux/smp.h>
 #endif
+#ifdef CONFIG_BIGPHYS_AREA
+#include <linux/bigphysarea.h>
+#endif
+
 
 extern char *get_options(char *str, int *ints);
 extern void set_device_ro(kdev_t dev,int flag);
@@ -400,3 +404,13 @@
 
 /* library functions */
 EXPORT_SYMBOL(strnicmp);
+
+/* Large physical area memory management */
+#ifdef CONFIG_BIGPHYS_AREA
+EXPORT_SYMBOL(bigphysarea_alloc);
+EXPORT_SYMBOL(bigphysarea_free);
+EXPORT_SYMBOL(bigphysarea_alloc_pages);
+EXPORT_SYMBOL(bigphysarea_free_pages);
+EXPORT_SYMBOL(bigphysarea);
+#endif
+
diff -u --recursive --unidirectional-new-file linux-2.1.126/mm/Makefile linux-2.1.126-bigphysarea/mm/Makefile
--- linux-2.1.126/mm/Makefile	Sun May  3 13:14:31 1998
+++ linux-2.1.126-bigphysarea/mm/Makefile	Thu Oct 29 07:55:53 1998
@@ -10,6 +10,7 @@
 O_TARGET := mm.o
 O_OBJS	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
 	    vmalloc.o slab.o \
-	    swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o
+	    swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o \
+	    bigphysarea.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --unidirectional-new-file linux-2.1.126/mm/bigphysarea.c linux-2.1.126-bigphysarea/mm/bigphysarea.c
--- linux-2.1.126/mm/bigphysarea.c	Wed Dec 31 17:00:00 1969
+++ linux-2.1.126-bigphysarea/mm/bigphysarea.c	Thu Nov  5 11:31:14 1998
@@ -0,0 +1,449 @@
+/* linux/mm/bigphysarea.c, M. Welsh (mdw@cs.cornell.edu)
+ * Copyright (c) 1996 by Matt Welsh.
+ * Extended by Roger Butenuth (butenuth@uni-paderborn.de), October 1997
+ *
+ * This is a set of routines which allow you to reserve a large (?) 
+ * amount of physical memory at boot-time, which can be allocated/deallocated
+ * by drivers. This memory is intended to be used for devices such as 
+ * video framegrabbers which need a lot of physical RAM (above the amount
+ * allocated by kmalloc). This is by no means efficient or recommended;
+ * to be used only in extreme circumstances.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/bigphysarea.h>
+
+#include <asm/io.h>
+#include <linux/slab.h>
+#include <asm/pgtable.h>
+
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <asm/system.h>
+
+#ifndef CONFIG_BIGPHYS_AREA
+
+/*
+ *  If we are not using the bigphysarea patch, disable the pfree and
+ * pmalloc system calls
+ */
+caddr_t sys_pmalloc(void)
+{
+  printk("pmalloc called by pid %d without bigphysarea patch enabled\n",
+	current->pid );
+  return NULL;
+}
+void sys_pfree(void)
+{
+  printk("pfree called by pid %d without bigphysarea patch enabled\n",
+	current->pid );
+}
+
+#else
+
+/*
+ *  Big-Phys-Area patch is enabled, so we'll compile the routines
+ * into it now.
+ */
+typedef struct range_struct {
+  struct range_struct *next;
+  caddr_t base;			/* base of allocated block */
+  size_t  size;			/* size in bytes */
+} range_t;
+
+static int bigphysarea_pages = 0;
+static int init_level = 0;
+/*
+ * 0: nothing initialized
+ * 1: bigphysarea_pages initialized
+ * 2: free list initialized
+ */
+static range_t *free_list = NULL;
+static range_t *used_list = NULL;
+
+caddr_t bigphysarea;
+
+void bigphysarea_setup(char *str, int *ints)
+{
+	if (ints[0] != 1) {
+		printk("bigphysarea_setup: Usage: bigphysarea=<number of pages>\n");
+	} else {
+		bigphysarea_pages = ints[1];
+	}
+}
+
+unsigned long bigphysarea_init(unsigned long mem_start, unsigned long mem_end) {
+	if (bigphysarea_pages == 0)
+		return mem_start;
+
+	bigphysarea = (caddr_t)((mem_start + (PAGE_SIZE - 1)) &
+				~(PAGE_SIZE - 1));
+	
+	init_level = 1;
+
+	printk("bigphysarea: Allocated %d pages at 0x%08lx.\n",
+	       bigphysarea_pages, (unsigned long)bigphysarea);
+
+	return (unsigned long)(bigphysarea + (bigphysarea_pages * PAGE_SIZE));
+}
+
+/*
+ * When we have pages but don't have a freelist, put all pages in
+ * one free list entry. Return 0 on success, 1 on error.
+ */
+static int init2(int priority)
+{
+	if (init_level == 1) {
+		free_list = kmalloc(sizeof(range_t), priority);
+		if (free_list != NULL) {
+			free_list->next = NULL;
+			free_list->base = bigphysarea;
+			free_list->size = bigphysarea_pages * PAGE_SIZE;
+			init_level = 2;
+			return 0;
+		} else 
+			return 1;
+	} else
+		return 1;
+}
+
+
+/*
+ * Allocate `count' pages from the big physical area. Pages are aligned to
+ * a multiple of `align'. `priority' has the same meaning in kmalloc, it
+ * is needed for management information.
+ * This function may not be called from an interrupt!
+ */
+caddr_t bigphysarea_alloc_pages(int count, int align, int priority)
+{
+	range_t *range, **range_ptr, *new_range, *align_range;
+	caddr_t aligned_base;
+
+	if (init_level < 2)
+		if (init2(priority))
+			return 0;
+	new_range   = NULL;
+	align_range = NULL;
+
+	if (align == 0)
+		align = PAGE_SIZE;
+	else
+		align = align * PAGE_SIZE;
+	/*
+	 * Search a free block which is large enough, even with alignment.
+	 */
+	range_ptr = &free_list;
+	while (*range_ptr != NULL) {
+		range = *range_ptr;
+		aligned_base =
+		  (caddr_t)((((long)range->base + align - 1) / align) * align);
+		if (aligned_base + count * PAGE_SIZE <= 
+		    range->base + range->size)
+			break;
+	     range_ptr = &range->next;
+	}
+	if (*range_ptr == NULL)
+		return 0;
+	range = *range_ptr;
+	/*
+	 * When we have to align, the pages needed for alignment can
+	 * be put back to the free pool.
+	 * We check here if we need a second range data structure later
+	 * and allocate it now, so that we don't have to check for a
+	 * failed kmalloc later.
+	 */
+	if (aligned_base - range->base + count * PAGE_SIZE < range->size) {
+		new_range = kmalloc(sizeof(range_t), priority);
+		if (new_range == NULL)
+			return NULL;
+	}
+	if (aligned_base != range->base) {
+		align_range = kmalloc(sizeof(range_t), priority);
+		if (align_range == NULL) {
+			if (new_range != NULL)
+				kfree(new_range);
+			return NULL;
+		}
+		align_range->base = range->base;
+		align_range->size = aligned_base - range->base;
+		range->base = aligned_base;
+		range->size -= align_range->size;
+		align_range->next = range;
+		*range_ptr = align_range;
+		range_ptr = &align_range->next;
+	}
+	if (new_range != NULL) {
+		/*
+		 * Range is larger than needed, create a new list element for
+		 * the used list and shrink the element in the free list.
+		 */
+		new_range->base        = range->base;
+		new_range->size        = count * PAGE_SIZE;
+		range->base = new_range->base + new_range->size;
+		range->size = range->size - new_range->size;
+	} else {
+		/*
+		 * Range fits perfectly, remove it from free list.
+		 */
+		*range_ptr = range->next;
+		new_range = range;
+	}
+	/*
+	 * Insert block into used list
+	 */
+	new_range->next = used_list;
+	used_list = new_range;
+
+	return new_range->base;
+}
+
+/*
+ * Free pages allocated with `bigphysarea_alloc_pages'. `base' must be an
+ * address returned by `bigphysarea_alloc_pages'.
+ * This function my not be called from an interrupt!
+ */
+void bigphysarea_free_pages(caddr_t base)
+{
+	range_t *prev, *next, *range, **range_ptr;
+  
+	/*
+	 * Search the block in the used list.
+	 */
+	for (range_ptr = &used_list;
+	     *range_ptr != NULL;
+	     range_ptr = &(*range_ptr)->next)
+		if ((*range_ptr)->base == base)
+			break;
+	if (*range_ptr == NULL) {
+		printk("bigphysarea_free_pages(%p), not allocated!\n", base);
+		return;
+	}
+	range = *range_ptr;
+	/*
+	 * Remove range from the used list:
+	 */
+	*range_ptr = (*range_ptr)->next;
+	/*
+	 * The free-list is sorted by address, search insertion point
+	 * and insert block in free list.
+	 */
+	for (range_ptr = &free_list, prev = NULL;
+	     *range_ptr != NULL;
+	     prev = *range_ptr, range_ptr = &(*range_ptr)->next)
+		if ((*range_ptr)->base >= base)
+			break;
+	range->next  = *range_ptr;
+	*range_ptr   = range;
+	/*
+	 * Concatenate free range with neighbors, if possible.
+	 * Try for upper neighbor (next in list) first, then
+	 * for lower neighbor (predecessor in list).
+	 */
+	if (range->next != NULL &&
+	    range->base + range->size == range->next->base) {
+		next = range->next;
+		range->size += range->next->size;
+		range->next = next->next;
+		kfree(next);
+	}
+	if (prev != NULL &&
+	    prev->base + prev->size == range->base) {
+		prev->size += prev->next->size;
+		prev->next = range->next;
+		kfree(range);
+	}
+}
+
+caddr_t bigphysarea_alloc(int size)
+{
+	int pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+
+	return bigphysarea_alloc_pages(pages, 1, GFP_KERNEL);
+}
+
+void bigphysarea_free(caddr_t addr, int size)
+{
+	(void)size;
+	bigphysarea_free_pages(addr);
+}
+
+int get_bigphysarea_info(char *buf)
+{
+	char    *p = buf;
+	range_t *ptr;
+	int     free_count, free_total, free_max;
+	int     used_count, used_total, used_max;
+
+	if (init_level == 1)
+	  init2(GFP_KERNEL);
+
+	free_count = 0;
+	free_total = 0;
+	free_max   = 0;
+	for (ptr = free_list; ptr != NULL; ptr = ptr->next) {
+		free_count++;
+		free_total += ptr->size;
+		if (ptr->size > free_max)
+			free_max = ptr->size;
+	}
+
+	used_count = 0;
+	used_total = 0;
+	used_max   = 0;
+	for (ptr = used_list; ptr != NULL; ptr = ptr->next) {
+		used_count++;
+		used_total += ptr->size;
+		if (ptr->size > used_max)
+			used_max = ptr->size;
+	}
+
+	if (bigphysarea_pages == 0) {
+		p += sprintf(p, "No big physical area allocated!\n");
+		return  p - buf;
+	}
+	  
+	p += sprintf(p, "Big physical area, size %ld kB\n",
+		     bigphysarea_pages * PAGE_SIZE / 1024);
+	p += sprintf(p, "                       free list:             used list:\n");
+	p += sprintf(p, "number of blocks:      %8d kB            %8d kB\n",
+		     free_count, used_count);
+	p += sprintf(p, "size of largest block: %8d kB            %8d kB\n",
+		     free_max / 1024, used_max / 1024);
+	p += sprintf(p, "total:                 %8d kB            %8d kB\n",
+		     free_total / 1024, used_total /1024);
+
+	return  p - buf;
+}
+
+
+/*
+ *  System call to allocate a physical linear buffer
+ * Added by Tramm Hudson (tbhudso@cs.sandia.gov) 26 October 1998
+ */
+caddr_t sys_pmalloc( int count, int align )
+{
+  caddr_t p_base, v_base;
+  size_t len = count << PAGE_SHIFT;
+
+  printk( "pmalloc: %d pages aligned 0x%x (len=%d)\n", 
+	count, align, len );
+
+  /*
+   *  Now that we know that we have the space in the user's space,
+   * we go ahead and allocate the linear buffer.  
+   */
+  p_base = bigphysarea_alloc_pages( count, align, GFP_KERNEL );
+  if( !p_base ) {
+    printk( "pmalloc: unable to allocate %d pages for pid %d\n",
+	count, current->pid );
+    return NULL;
+  }
+
+  printk( "pmalloc: pages based in base=%p\n", p_base );
+  v_base = map_region( current, (caddr_t)((unsigned long)p_base & ~IDENT_ADDR), NULL, len );
+  if( !v_base ) {
+    printk( "pmalloc: map failed!\n" );
+    bigphysarea_free_pages( p_base );
+  }
+
+  /*
+   *  The user wants the address of the buffer in the process's
+   * address space, so we return the virtual address of the buffer.
+   */
+  return v_base;
+}
+
+caddr_t v2p( struct task_struct *task, caddr_t v_base )
+{
+  pgd_t *pgd;
+  pmd_t *pmd;
+  pte_t *pte;
+  caddr_t p_base;
+
+
+/*  printk( "v2p: Resolving virtual address 0x%p\n", v_base ); */
+
+  pgd = pgd_offset( task->mm, (unsigned long) v_base );
+  if( pgd_none( *pgd ) ) {
+    printk( "v2p: No page dir at %p\n", v_base );
+    return NULL;
+  }
+  if( pgd_bad( *pgd ) ) {
+    printk( "v2p: Bad page dir at %p\n", v_base );
+    return NULL;
+  }
+
+  pmd = pmd_offset( pgd, (unsigned long) v_base );
+  if( pmd_none( *pmd ) ) {
+    printk( "v2p; No page middle dir at %p\n", v_base );
+    return NULL;
+  }
+  if( pmd_bad( *pmd ) ) {
+    printk( "v2p: Bad page middle dir at %p\n", v_base );
+    return NULL;
+  }
+  
+  pte = pte_offset( pmd, (unsigned long) v_base );
+  if( pte_none( *pte ) ) {
+    printk( "v2p: No page table entry for %p\n", v_base );
+    return NULL;
+  }
+  if( !pte_present( *pte ) ) {
+    printk( "v2p: Page at %p not present.  Way wrong\n", v_base );
+    return NULL;
+  }
+
+  p_base = (caddr_t) pte_page(*pte);
+  p_base += (unsigned long)v_base & ~PAGE_MASK;
+  (unsigned long) p_base |= IDENT_ADDR;
+
+  /* printk( "v2p: %p -> %p\n", v_base, p_base ); */
+
+  return p_base;
+}
+
+/*
+ *  System call to free a linear buffer
+ */
+void sys_pfree( caddr_t v_base )
+{
+  /*
+   *  Need to learn how to map virtual address to
+   * physical address for the current process
+   */
+  caddr_t p_base = v2p( current, v_base );
+
+  printk( "pfree: base=%p -> %p\n", v_base, p_base );
+
+  if( !v_base ) return;
+  
+  bigphysarea_free_pages( p_base );
+}
+
+#endif
+
diff -u --recursive --unidirectional-new-file linux-2.1.126/mm/mmap.c linux-2.1.126-bigphysarea/mm/mmap.c
--- linux-2.1.126/mm/mmap.c	Thu Aug 20 15:47:43 1998
+++ linux-2.1.126-bigphysarea/mm/mmap.c	Tue Nov  3 14:47:54 1998
@@ -704,3 +704,81 @@
 	if(!mm_cachep)
 		panic("vma_init: Cannot alloc mm_struct cache.");
 }
+
+
+/*
+ *  Map a physical region starting at p_base of length len into the
+ * user's address space at an arbitrary virtual address.  We first
+ * check for enough free space in the user's VM, then allocate a VMA
+ * and fill it in.  We then merge the segments in.
+ *
+ * Written by Tramm Hudson (tbhudso@cs.sandia.gov) 26 October 1998
+ *
+ * Used by the bigphysarea patch to support large physical buffers
+ * as part of the Computational Plant project at Sandia Labs.
+ */
+caddr_t map_region(
+	struct task_struct *tsk, caddr_t p_base, caddr_t v_base, size_t len )
+{
+    struct mm_struct *mm = tsk->mm;
+    struct vm_area_struct *vma;
+
+    /*
+     *  Find a free region in user space
+     */
+    if( !v_base ) {
+      if( !(v_base = (caddr_t) get_unmapped_area( 0, len )) ) {;
+        printk( "map_region: no space in userland for %d words\n", len );
+        return NULL;
+      }
+    }
+
+   /*
+    *  Fill in the newly allocated vma structure.
+    * This code is mostly copied from the do_mmap() call
+    */
+    vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+    if( !vma ) {
+      printk( "map_region: unable to allocate vma\n" );
+      return NULL;
+    }
+
+    vma->vm_mm = mm;
+    vma->vm_start = (unsigned long) v_base;
+    vma->vm_end = (unsigned long) (v_base) + len;
+    vma->vm_flags = vm_flags( PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED )			  | mm->def_flags
+		  | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+    vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
+    vma->vm_ops = NULL;
+    vma->vm_offset = 0;
+    vma->vm_file = NULL;
+    vma->vm_pte = 0;
+
+    /* Make sure that the pages are locked down */
+    mm->locked_vm += len >> PAGE_SHIFT;
+
+    /* Check against address space limits */
+    if( (mm->total_vm << PAGE_SHIFT)+len > tsk->rlim[RLIMIT_AS].rlim_cur )
+    {
+      printk( "map_region: not enough virtual space\n" );
+      kmem_cache_free( vm_area_cachep, vma );
+      return NULL;
+    }
+
+    /* Build the page tables */
+    if( 0 > remap_page_range( (unsigned long) v_base, (unsigned long) p_base,
+	len, PAGE_SHARED ) )
+    {
+      printk( "map_region: remap_range failed\n" );
+      kmem_cache_free( vm_area_cachep, vma );
+      return NULL;
+    }
+      
+
+    /* Merge our vma segment */
+    insert_vm_struct( mm, vma );
+    merge_segments( mm, vma->vm_start, vma->vm_end );
+    mm->total_vm += (len>>PAGE_SHIFT);
+
+    return v_base;
+}