diff -u -p -L linux/arch/i386/config.in.orig linux/arch/i386/config.in
--- linux/arch/i386/config.in
+++ linux/arch/i386/config.in	Tue Jan 11 20:39:50 2000
@@ -40,6 +40,7 @@ choice 'Maximum Physical Memory' \
 bool 'Math emulation' CONFIG_MATH_EMULATION
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
 bool 'Symmetric multi-processing support' CONFIG_SMP
+bool 'Bigphysarea support' CONFIG_BIGPHYSAREA
 endmenu
 
 mainmenu_option next_comment
diff -u -p -L linux/arch/i386/kernel/ptrace.c.orig linux/arch/i386/kernel/ptrace.c
--- linux/arch/i386/kernel/ptrace.c
+++ linux/arch/i386/kernel/ptrace.c	Tue Jan 11 20:46:27 2000
@@ -17,6 +17,9 @@
 #include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/debugreg.h>
+#ifdef CONFIG_BIGPHYSAREA
+#include <asm/io.h>
+#endif
 
 /*
  * does not yet catch signals sent when the child dies.
@@ -121,11 +124,21 @@ repeat:
 		return 0;
 	}
 	page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) >= max_mapnr)
-		return 0;
-	page += addr & ~PAGE_MASK;
-	return *(unsigned long *) page;
+	if (MAP_NR(page) >= max_mapnr) {
+		/* for high addresses, map the page into kernel space */
+		unsigned long result, vpage;
+		vpage = (unsigned long)ioremap(__pa(page), PAGE_SIZE);
+		if (!vpage) {
+			printk("ptrace: out of memory\n");
+			return 0;
+		}
+		result = *(unsigned long *) (vpage + (addr & ~PAGE_MASK));
+		iounmap((void*)vpage);
+		return result;
+	} else {
+		page += addr & ~PAGE_MASK;
+		return *(unsigned long *) page;
+	}
 }
 
 /*
@@ -193,9 +206,19 @@ repeat:
 			force_sig(SIGKILL, tsk);
 		return;
 	}
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) < max_mapnr)
+	if (MAP_NR(page) < max_mapnr) {
 		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+	} else {
+		/* for high addresses, map the page into kernel space */
+		unsigned long vpage;
+		vpage = (unsigned long)ioremap(__pa(page), PAGE_SIZE);
+		if (!vpage) {
+			printk("ptrace: out of memory\n");
+			return;
+		}
+		*(unsigned long *) (vpage + (addr & ~PAGE_MASK)) = data;
+		iounmap((void*)(vpage));
+	}
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 /* this should also re-instate whatever read-only mode there was before */
 	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
diff -u -p -L linux/fs/proc/array.c.orig linux/fs/proc/array.c
--- linux/fs/proc/array.c
+++ linux/fs/proc/array.c	Tue Jan 11 20:47:15 2000
@@ -1308,6 +1308,7 @@ extern int get_cpuinfo(char *);
 extern int get_pci_list(char *);
 extern int get_md_status (char *);
 extern int get_rtc_status (char *);
+extern int get_bigphysarea_info(char *);
 extern int get_locks_status (char *, char **, off_t, int);
 extern int get_swaparea_info (char *);
 extern int get_hardware_list(char *);
@@ -1397,6 +1398,10 @@ static long get_root_array(char * page, 
 #ifdef CONFIG_SGI_DS1286
 		case PROC_RTC:
 			return get_ds1286_status(page);
+#endif
+#ifdef CONFIG_BIGPHYSAREA
+		case PROC_BIGPHYSAREA:
+			return get_bigphysarea_info(page);
 #endif
 		case PROC_LOCKS:
 			return get_locks_status(page, start, offset, length);
diff -u -p -L linux/fs/proc/root.c.orig linux/fs/proc/root.c
--- linux/fs/proc/root.c
+++ linux/fs/proc/root.c	Tue Jan 11 20:49:20 2000
@@ -640,6 +640,13 @@ static struct proc_dir_entry proc_root_d
 	0, &proc_array_inode_operations
 };
 #endif
+#ifdef CONFIG_BIGPHYSAREA
+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,
@@ -719,6 +726,9 @@ __initfunc(void proc_root_init(void))
 #endif
 #ifdef CONFIG_SGI_DS1286
 	proc_register(&proc_root, &proc_root_ds1286);
+#endif
+#ifdef CONFIG_BIGPHYSAREA
+	proc_register(&proc_root, &proc_root_bigphysarea);
 #endif
 	proc_register(&proc_root, &proc_root_locks);
 
diff -u -p -L linux/include/linux/bigphysarea.h.orig linux/include/linux/bigphysarea.h
--- linux/include/linux/bigphysarea.h
+++ linux/include/linux/bigphysarea.h	Tue Jan 11 20:50:22 2000
@@ -0,0 +1,64 @@
+/* linux/mm/bigphysarea.h, 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.
+ *
+ */
+
+#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 m\
+em_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
+/* linux/mm/bigphysarea.h, 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.
+ *
+ */
+
+#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 m\
+em_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 -p -L linux/include/linux/proc_fs.h.orig linux/include/linux/proc_fs.h
--- linux/include/linux/proc_fs.h
+++ linux/include/linux/proc_fs.h	Tue Jan 11 21:06:26 2000
@@ -44,6 +44,7 @@ enum root_directory_inos {
 	PROC_SWAP,
 	PROC_MD,
 	PROC_RTC,
+	PROC_BIGPHYSAREA,
 	PROC_LOCKS,
 	PROC_HARDWARE,
 	PROC_SLABINFO,
diff -u -p -L linux/init/main.c.orig linux/init/main.c
--- linux/init/main.c
+++ linux/init/main.c	Tue Jan 11 21:09:37 2000
@@ -366,6 +366,9 @@ extern void cpqarray_setup(char *str, in
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
 #endif
+#if defined(CONFIG_BIGPHYSAREA)
+extern void bigphysarea_setup(char *str, int *ints);
+#endif
 #if defined(CONFIG_QUOTA)
 extern void dquot_init_hash(void);
 #endif
@@ -948,6 +951,9 @@ static struct kernel_param cooked_params
 #ifdef CONFIG_BLK_CPQ_DA
 	{ "smart2=", cpqarray_setup },
 #endif
+#ifdef CONFIG_BIGPHYSAREA
+	{ "bigphysarea=", bigphysarea_setup },
+#endif
 	{ 0, 0 }
 };
 
@@ -1259,6 +1265,9 @@ asmlinkage void __init start_kernel(void
 		    "disabling it.\n",initrd_start,memory_start);
 		initrd_start = 0;
 	}
+#endif
+#ifdef CONFIG_BIGPHYSAREA
+	memory_start = bigphysarea_init(memory_start,memory_end);
 #endif
 	mem_init(memory_start,memory_end);
 	kmem_cache_sizes_init();
diff -u -p -L linux/kernel/ksyms.c.orig linux/kernel/ksyms.c
--- linux/kernel/ksyms.c
+++ linux/kernel/ksyms.c	Tue Jan 11 21:11:33 2000
@@ -39,6 +39,9 @@
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/capability.h>
+#if defined(CONFIG_BIGPHYSAREA)
+#include <linux/bigphysarea.h>
+#endif
 
 #if defined(CONFIG_PROC_FS)
 #include <linux/proc_fs.h>
@@ -113,6 +116,18 @@ EXPORT_SYMBOL(update_vm_cache_conditiona
 EXPORT_SYMBOL(vmtruncate);
 EXPORT_SYMBOL(find_vma);
 EXPORT_SYMBOL(get_unmapped_area);
+#ifdef CONFIG_BIGPHYSAREA
+/* following symbols are used by the SCI driver */
+EXPORT_SYMBOL(page_cache_size);
+EXPORT_SYMBOL(page_hash_table);
+EXPORT_SYMBOL(zap_page_range);
+EXPORT_SYMBOL(insert_vm_struct);
+/* Large physical area memory management */
+EXPORT_SYMBOL(bigphysarea_alloc);
+EXPORT_SYMBOL(bigphysarea_free);
+EXPORT_SYMBOL(bigphysarea_alloc_pages);
+EXPORT_SYMBOL(bigphysarea_free_pages);
+#endif
 
 /* filesystem internal functions */
 EXPORT_SYMBOL(in_group_p);
diff -u -p -L linux/mm/Makefile.orig linux/mm/Makefile
--- linux/mm/Makefile
+++ linux/mm/Makefile	Tue Jan 11 21:12:52 2000
@@ -12,4 +12,8 @@ O_OBJS	 := memory.o mmap.o filemap.o mpr
 	    vmalloc.o slab.o \
 	    swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o
 
+ifeq ($(CONFIG_BIGPHYSAREA),y)
+O_OBJS += bigphysarea.o
+endif
+
 include $(TOPDIR)/Rules.make
diff -u -p -L linux/mm/bigphysarea.c.orig linux/mm/bigphysarea.c
--- linux/mm/bigphysarea.c
+++ linux/mm/bigphysarea.c	Tue Jan 11 21:13:15 2000
@@ -0,0 +1,337 @@
+/* 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/string.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/bigphysarea.h>
+
+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;
+/*
+ * 0: nothing initialized
+ * 1: bigphysarea_pages initialized
+ * 2: free list initialized
+ */
+static int init_level = 0;
+
+/*
+ * The free list and the used list are protected by one lock.
+ */
+static spinlock_t big_lock = SPIN_LOCK_UNLOCKED;
+static range_t *free_list = NULL;
+static range_t *used_list = NULL;
+
+caddr_t bigphysarea = 0;
+
+void bigphysarea_setup(char *str, int *ints)
+{
+	if (ints[0] == 1)
+		bigphysarea_pages = ints[1];
+	else
+	        bigphysarea_pages = 0;
+}
+
+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)
+{
+	int res;
+
+	spin_lock(&big_lock);	/* >>>>>>>>>> */
+	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;
+			res = 0;
+		} else 
+			res = 1;
+	} else
+		res = 1;
+
+	spin_unlock(&big_lock);	/* <<<<<<<<<< */
+	return res;
+}
+
+
+/*
+ * 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, this is the reason
+ * we can use lock functions without disabling all interrupts.
+ */
+caddr_t bigphysarea_alloc_pages(int count, int align, int priority)
+{
+	range_t *range, **range_ptr, *new_range, *align_range;
+	caddr_t aligned_base;
+	caddr_t res = 0;
+
+	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;
+
+	spin_lock(&big_lock);	/* >>>>>>>>>> */
+	/*
+	 * 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) {
+		res = 0;
+		goto ret_label;
+	}
+	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) {
+			res = 0;
+			goto ret_label;
+		}
+	}
+	if (aligned_base != range->base) {
+		align_range = kmalloc(sizeof(range_t), priority);
+		if (align_range == NULL) {
+			if (new_range != NULL)
+				kfree(new_range);
+			res = 0;
+			goto ret_label;
+		}
+		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;
+
+	res = new_range->base;
+ ret_label:
+	spin_unlock(&big_lock);	/* <<<<<<<<<< */
+	return res;
+
+}
+
+
+/*
+ * 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, for this reason we 
+ * can use a lock without interrupt disabling.
+ */
+void bigphysarea_free_pages(caddr_t base)
+{
+	range_t *prev, *next, *range, **range_ptr;
+  
+	spin_lock(&big_lock);	/* >>>>>>>>>> */
+	/*
+	 * 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(0x%08x), not allocated!\n",
+		       (unsigned)base);
+		goto ret_label;
+	}
+	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);
+	}
+ ret_label:
+	spin_unlock(&big_lock);	/* <<<<<<<<<< */
+}
+
+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);
+
+	spin_lock(&big_lock);	/* >>>>>>>>>> */
+	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;
+	}
+	spin_unlock(&big_lock);	/* <<<<<<<<<< */
+
+	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               %8d\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;
+}

