diff -u -r -P 2.2.1/Documentation/Configure.help current/Documentation/Configure.help --- 2.2.1/Documentation/Configure.help Wed Jan 20 20:05:32 1999 +++ current/Documentation/Configure.help Sun Feb 7 20:37:05 1999 @@ -229,6 +229,22 @@ Most users will answer N here. +Hugeram Ramdisk +CONFIG_BLK_DEV_HUGERAMD + Saying Y here makes it possible to use the memory above 1 gigabyte + as a ramdisk. This only works if you have enabled CONFIG_HUGEMEM. + + The ramdisk can be accessed through block special files + /dev/hugeram0 ... /dev/hugeram7, with major number 126 and + minor numbers 0..7 (do "man mknod" for help how to create them) + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called hugeramd.o. + + Most users will answer N here. + Network Block Device support CONFIG_BLK_DEV_NBD Saying Y here will allow your computer to be a client for network @@ -8366,6 +8382,25 @@ just add about 3k to your kernel. See Documentation/mtrr.txt for more information. + +Huge memory support +CONFIG_HUGEMEM + Enables kernel support for really huge amounts of RAM (beyond 1 Gigabyte) + + Linux currently supports up to 960 MB of RAM on Intel and compatible + computers. + If you have more memory, there are two things you can do: + + 1: Increase manually the limit to 1984MB. + Read the note in include/linux/page.h to do this. + 2: Use the RAM above the 960MB limit (or above 1984MB if you applied 1:) + for special devices such as a HugeRamD ramdisk. + + Saying Y here makes it possible to use the solution 2: + use the RAM above the limit as a ramdisk. + + Note that to actually enable this ramdisk, you must also say Y to the + "Huge Ramdisk support" below. Main CPU frequency, only for DEC alpha machine CONFIG_FT_ALPHA_CLOCK diff -u -r -P 2.2.1/arch/i386/config.in current/arch/i386/config.in --- 2.2.1/arch/i386/config.in Wed Jan 20 19:18:53 1999 +++ current/arch/i386/config.in Fri Feb 5 18:38:29 1999 @@ -36,6 +36,7 @@ bool 'Math emulation' CONFIG_MATH_EMULATION bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP +bool 'Huge memory support' CONFIG_HUGEMEM endmenu mainmenu_option next_comment diff -u -r -P 2.2.1/arch/i386/kernel/Makefile current/arch/i386/kernel/Makefile --- 2.2.1/arch/i386/kernel/Makefile Wed Jan 20 19:18:53 1999 +++ current/arch/i386/kernel/Makefile Sun Feb 7 00:27:30 1999 @@ -26,6 +26,10 @@ O_OBJS += mca.o endif +ifdef CONFIG_HUGEMEM +O_OBJS += hugemem.o +endif + ifeq ($(CONFIG_MTRR),y) OX_OBJS += mtrr.o else diff -u -r -P 2.2.1/arch/i386/kernel/hugemem.c current/arch/i386/kernel/hugemem.c --- 2.2.1/arch/i386/kernel/hugemem.c Thu Jan 1 01:00:00 1970 +++ current/arch/i386/kernel/hugemem.c Sun Feb 7 22:05:06 1999 @@ -0,0 +1,158 @@ +/* + * linux/arch/i386/kernel/hugemem.c + * + * Written 1999 by Manfred Spraul + */ + +#include +#include +#include +#include +#include +#include + +/* + global variables: + */ + +int hugemem_startpg; /* number of the first page managed by hugemem */ +int hugemem_len = 0; +unsigned char* hugemem_bitmap = NULL; + +spinlock_t hugemem_lock = SPIN_LOCK_UNLOCKED; + +/* + internal functions: + */ + +int hm_init(void); + +/* + This function is called very early, it cannot call + any other kernel function. + Defer the actual initialization. + */ + +void init_hugemem(int memstart, int memend) +{ + memstart = (memstart + PAGE_SIZE-1) & PAGE_MASK; + memend = memend & PAGE_MASK; + + hugemem_startpg = memstart/PAGE_SIZE; + hugemem_len = (memend-memstart)/PAGE_SIZE/HM_PAGES_PER_BIT; +} + +int alloc_hugemem(int size) +{ + int result; + int i, missing; + + if(hugemem_len == 0) + return -1; + + if(size == 0) + return -1; + + spin_lock(&hugemem_lock); + + if(hugemem_bitmap == NULL) { + if(!hm_init()) { + spin_unlock(&hugemem_lock); + return -1; + } + } + + size = (size+HM_PAGES_PER_BIT-1)/HM_PAGES_PER_BIT; + + result = -1; + missing = size; + for(i=0;i>(i&0x07))) == 0) { + if(result==-1) { + missing = size; + result = i; + } + missing--; + if(missing == 0) + break; + } else { + result = -1; + } + } + if(missing != 0) + { + spin_unlock(&hugemem_lock); + return -1; + } + for(i=result;i>(i&0x07); + + spin_unlock(&hugemem_lock); + return result*HM_PAGES_PER_BIT+hugemem_startpg; +} + +void free_hugemem(int startpg, int size) +{ + startpg -= hugemem_startpg; + size = (size+HM_PAGES_PER_BIT-1)/HM_PAGES_PER_BIT; + + if((size > hugemem_len) || (size==0) || (startpg&(HM_PAGES_PER_BIT-1))) { + printk(KERN_DEBUG "free_hugemem: invalid parameter."); + return; + } + if(hugemem_bitmap == NULL) + return; + + spin_lock(&hugemem_lock); + + startpg /= HM_PAGES_PER_BIT; + while(size != 0) { + hugemem_bitmap[startpg/8] &= ~(0x80>>(startpg & 0x07)); + startpg++; + size--; + } + spin_unlock(&hugemem_lock); + return; +} + +/* pmax can be NULL, returns the size of the largest free area. */ +int getfree_hugemem(int* pmax) +{ + int i, found, max; + + spin_lock(&hugemem_lock); + + if(hugemem_bitmap == NULL) { + if(!hm_init()) { + spin_unlock(&hugemem_lock); + return -1; + } + } + + if(pmax != NULL) + *pmax = hugemem_len*HM_PAGES_PER_BIT; + found = 0; + max = 0; + + for(i=0;i>(i&0x07))) == 0) { + found++; + if(found > max) + max = found; + } else { + found = 0;; + } + } + spin_unlock(&hugemem_lock); + return max*HM_PAGES_PER_BIT; +} + +int hm_init(void) +{ + hugemem_bitmap = kmalloc((hugemem_len+7)/8,GFP_ATOMIC); + if(hugemem_bitmap == NULL) + return 0; + memset(hugemem_bitmap,0,(hugemem_len+7)/8); + return 1; +} + diff -u -r -P 2.2.1/arch/i386/kernel/i386_ksyms.c current/arch/i386/kernel/i386_ksyms.c --- 2.2.1/arch/i386/kernel/i386_ksyms.c Tue Jan 19 20:02:59 1999 +++ current/arch/i386/kernel/i386_ksyms.c Fri Feb 5 18:38:29 1999 @@ -17,6 +17,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); @@ -40,6 +41,7 @@ EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(init_mm); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); @@ -109,4 +111,9 @@ #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); +#endif + +#ifdef CONFIG_HUGEMEM +EXPORT_SYMBOL(alloc_hugemem); +EXPORT_SYMBOL(free_hugemem); #endif diff -u -r -P 2.2.1/arch/i386/kernel/setup.c current/arch/i386/kernel/setup.c --- 2.2.1/arch/i386/kernel/setup.c Thu Jan 21 20:28:40 1999 +++ current/arch/i386/kernel/setup.c Mon Feb 8 20:17:01 1999 @@ -32,6 +32,9 @@ #ifdef CONFIG_BLK_DEV_RAM #include #endif +#ifdef CONFIG_HUGEMEM +#include +#endif #include #include #include @@ -327,11 +330,20 @@ *to = '\0'; *cmdline_p = command_line; +#ifdef CONFIG_HUGEMEM +#define VMALLOC_RESERVE (96<<20) /* more memory for vmalloc */ +#else #define VMALLOC_RESERVE (64 << 20) /* 64MB for vmalloc */ +#endif #define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) - +/* FIXME: debug code. */ +#undef MAXMEM +#define MAXMEM (32 << 20) if (memory_end > MAXMEM) { +#ifdef CONFIG_HUGEMEM + init_hugemem(MAXMEM,memory_end); +#endif memory_end = MAXMEM; printk(KERN_WARNING "Warning only %ldMB will be used.\n", MAXMEM>>20); diff -u -r -P 2.2.1/arch/i386/mm/Makefile current/arch/i386/mm/Makefile --- 2.2.1/arch/i386/mm/Makefile Fri Nov 1 10:56:43 1996 +++ current/arch/i386/mm/Makefile Fri Feb 5 16:06:55 1999 @@ -10,4 +10,8 @@ O_TARGET := mm.o O_OBJS := init.o fault.o ioremap.o extable.o +ifdef CONFIG_HUGEMEM +O_OBJS += hmcache.o +endif + include $(TOPDIR)/Rules.make diff -u -r -P 2.2.1/arch/i386/mm/hmcache.c current/arch/i386/mm/hmcache.c --- 2.2.1/arch/i386/mm/hmcache.c Thu Jan 1 01:00:00 1970 +++ current/arch/i386/mm/hmcache.c Mon Feb 8 20:32:25 1999 @@ -0,0 +1,378 @@ +/* + * arch/i386/mm/hmcache.o + * + * physical memory cache: + * + * (C) Copyright 1999 Manfred Spraul + * + * assumptions: + * - the offset field to __find_page is a byte offset. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* the size of this structure must be 32 bytes. */ +typedef struct hmc_page hmc_page_t; +struct hmc_page { + struct inode* inode; + unsigned long offset; + hmc_page_t *hash_next; + hmc_page_t *lru_newer; + /* 0x10: */ + hmc_page_t *hash_prev; + hmc_page_t *lru_older; + hmc_page_t *ihash_next; + hmc_page_t *ihash_prev; +}; + +#define HMC_DESC_PER_PAGE 128 + +unsigned long hmc_allocstart = 0; +unsigned long hmc_alloclen = 0; +unsigned long hmc_start; +unsigned long hmc_size; +hmc_page_t *hmc_desc = NULL; + +hmc_page_t *hmc_freelist = NULL; /* linked with the lru-field */ +hmc_page_t *hmc_lrunew = NULL; +hmc_page_t *hmc_lruold = NULL; + +spinlock_t hmc_lock = SPIN_LOCK_UNLOCKED; + +#define HM_PHASH_BITS 14 +#define HM_PHASH_SIZE (1 << HM_PHASH_BITS) +#define HM_PHASH_ALLOCORDER 4 + +#define HM_IHASH_BITS 10 +#define HM_IHASH_SIZE (1 << HM_IHASH_BITS) +#define HM_IHASH_ALLOCORDER 0 + +hmc_page_t **hmc_hash_table = NULL; +hmc_page_t ** hmc_ihash_table = NULL; +void* hmc_mapwnd = NULL; + + +/* #define HMC_DEBUG */ +#ifdef HMC_DEBUG + +static int ENABLE_HMC = 0; + +#define assert(x) if( !(x) ) __asm__ __volatile__ ("int3"); + +#else +#define ENABLE_HMC 1 +#define assert(x) do { } while (0) +#endif + +/* I never free the hash tables, they remain allocated. */ +static int _hmc_init(void) +{ + int i; + if(!ENABLE_HMC) + return -ENOMEM; + + assert(sizeof(hmc_page_t) == 32); + + i = getfree_hugemem(NULL); + hmc_allocstart = alloc_hugemem(i); + if(hmc_allocstart == 0) + return 0; + hmc_alloclen = i; + + if(hmc_hash_table == NULL) { + hmc_hash_table = (void*)__get_free_pages(__GFP_MED, + HM_PHASH_ALLOCORDER); + if(hmc_hash_table == NULL) + goto out_mem; + memset(hmc_hash_table,0,HM_PHASH_SIZE*sizeof(unsigned long)); + } + if(hmc_ihash_table == NULL) { + hmc_ihash_table = (void*)__get_free_pages(__GFP_MED, + HM_IHASH_ALLOCORDER); + if(hmc_ihash_table == NULL) + goto out_mem; + memset(hmc_ihash_table,0,HM_IHASH_SIZE*sizeof(unsigned long)); + } + hmc_size = (i+HMC_DESC_PER_PAGE)/(HMC_DESC_PER_PAGE+1); + hmc_start = hmc_allocstart + hmc_size; + assert( (hmc_alloclen - hmc_size) <= hmc_size*HMC_DESC_PER_PAGE); + hmc_size = hmc_alloclen - hmc_size; + + /* add a window for the cache descriptors: up to 24 MB */ + /* FIXME: ioremap should support 4 MB PTE's */ + hmc_desc = ioremap(hmc_allocstart*PAGE_SIZE,hmc_size*sizeof(hmc_page_t)); + if(hmc_desc == NULL) + goto out_mem; + if(hmc_mapwnd == NULL) + hmc_mapwnd = ioremap(hmc_allocstart*PAGE_SIZE,PAGE_SIZE); + + memset(hmc_desc,0,hmc_size*sizeof(hmc_page_t)); + hmc_freelist = &hmc_desc[0]; + hmc_desc[0].lru_older = NULL; + hmc_desc[0].lru_newer = &hmc_desc[1]; + + for(i=1;i> PAGE_SHIFT) +#define s(x) ((x)+((x)>>hashbits)) + return s(i+o) & ((1<hash_prev == NULL) || (p->hash_prev->hash_next == p) ); + assert( (p->hash_next == NULL) || (p->hash_next->hash_prev == p) ); + assert( (p->ihash_next == NULL) || (p->ihash_next->ihash_prev == p) ); + assert( (p->ihash_prev == NULL) || (p->ihash_prev->ihash_next == p) ); + assert( (p->lru_newer == NULL) || (p->lru_newer->lru_older == p) ); + assert( (p->lru_older == NULL) || (p->lru_older->lru_newer == p) ); +} + + +void hmc_unlinkpg(hmc_page_t* p) +{ + hmc_checkpg(p); + + if(p->hash_next != NULL) + p->hash_next->hash_prev = p->hash_prev; + if(p->hash_prev == NULL) + hmc_hash_table[hmc_gethash(p->inode, p->offset, HM_PHASH_BITS)] = p->hash_next; + else + p->hash_prev->hash_next = p->hash_next; + + if(p->ihash_next != NULL) + p->ihash_next->ihash_prev = p->ihash_prev; + if(p->ihash_prev == NULL) + hmc_ihash_table[hmc_gethash(p->inode, 0, HM_IHASH_BITS)] = p->ihash_next; + else + p->ihash_prev->ihash_next = p->ihash_next; + + if(p->lru_newer == NULL) + hmc_lrunew = p->lru_older; + else + p->lru_newer->lru_older = p->lru_older; + if(p->lru_older == NULL) + hmc_lruold = p->lru_newer; + else + p->lru_older->lru_newer = p->lru_newer; +} + +/* from mm/filemap.c */ +/* FIXME: race: which locks are required for changing these lists? */ +static inline void add_to_page_cache(struct page * page, + struct inode * inode, unsigned long offset, + struct page **hash) +{ + atomic_inc(&page->count); + page->flags = (page->flags & ~((1 << PG_uptodate) | (1 << PG_error))) | (1 << PG_referenced); + page->offset = offset; + add_page_to_inode_queue(inode, page); + __add_page_to_hash_queue(page, hash); +} + +struct page* hmc_getpage(hmc_page_t* phys) +{ + struct page* pg = NULL; + unsigned long pgaddr; + + hmc_checkpg(phys); + if( (phys->offset >= phys->inode->i_size) && + ( (pgaddr = __get_free_page(__GFP_MED)) != 0) ) + { + struct page** hash; + + pg = mem_map+ MAP_NR(pgaddr); + + hmc_copypg(phys, pg, 0); + hash = page_hash(phys->inode, phys->offset); + pg->inode = phys->inode; + pg->offset = phys->offset; + add_to_page_cache(pg, phys->inode, phys->offset, hash); + __free_page(pg); + } + hmc_unlinkpg(phys); + phys->lru_older = NULL; + phys->lru_newer = hmc_freelist; + if(hmc_freelist!= NULL) + hmc_freelist->lru_older = phys; + hmc_freelist = phys; + + return pg; +} + +struct page* hmc_findpage(struct inode* inode, unsigned long offset) +{ + struct page* out = NULL; + hmc_page_t* p; + + spin_lock(&hmc_lock); + if(!hmc_init()) + { + /* scan through the cache */ + p = hmc_hash_table[hmc_gethash(inode, offset, HM_PHASH_BITS)]; + while(p!=NULL) + { + hmc_checkpg(p); + if( (p->inode == inode) && + (p->offset == offset)) + { + out = hmc_getpage(p); + break; + } + p = p->hash_next; + } + } + spin_unlock(&hmc_lock); + return out; +} + +void hmc_invalidate_inode_pages(struct inode* inode) +{ + hmc_truncate_inode_pages(inode, 0); +} + +/* clearing partial pages is complicated, always discard the complete page. */ +void hmc_truncate_inode_pages(struct inode* inode, unsigned long start) +{ + spin_lock(&hmc_lock); + if(!hmc_init()) + { + hmc_page_t *p, *next; + +assert(0); + start = start & PAGE_MASK; + p = hmc_ihash_table[hmc_gethash(inode, 0, HM_IHASH_BITS)]; + while(p!=NULL) + { + next = p->ihash_next; + if((p->inode == inode) && + (p->offset >= start)) + { + hmc_unlinkpg(p); + p->lru_newer = hmc_lruold; + p->lru_older = NULL; + hmc_lruold = p; + } + p = next; + } + } + spin_unlock(&hmc_lock); +} + +/* the functions is called after the page was removed from the main cache. +FIXME: race: a new page is created before spin_lock() returns. */ + +extern struct inode swapper_inode; + +void hmc_add_page(struct page* page) +{ + if(page->flags & ((1 << PG_locked)|(1<inode == &swapper_inode) + return; // do not cache swapper entries. + spin_lock(&hmc_lock); + if(!hmc_init()) + { + hmc_page_t* p; + int hash; + if(hmc_freelist == NULL) { + p = hmc_lruold; + hmc_unlinkpg(hmc_lruold); + } else { + p = hmc_freelist; + if(p->lru_newer != NULL) + p->lru_newer->lru_older = NULL; + hmc_freelist = p->lru_newer; + } + + p->inode = page->inode; + p->offset = page->offset; + + hash = hmc_gethash(p->inode, p->offset, HM_PHASH_BITS); + if(hmc_hash_table[hash] != NULL) + hmc_hash_table[hash]->hash_prev = p; + p->hash_next = hmc_hash_table[hash]; + p->hash_prev = NULL; + hmc_hash_table[hash] = p; + + hash = hmc_gethash(p->inode, 0, HM_IHASH_BITS); + if(hmc_ihash_table[hash] != NULL) + hmc_ihash_table[hash]->ihash_prev = p; + p->ihash_next = hmc_ihash_table[hash]; + p->ihash_prev = NULL; + hmc_ihash_table[hash] = p; + + if(hmc_lrunew != NULL) + hmc_lrunew->lru_newer = p; + p->lru_newer = NULL; + p->lru_older = hmc_lrunew; + hmc_lrunew = p; + if(hmc_lruold == NULL) + hmc_lruold = p; + + hmc_copypg(p, page, 1); + hmc_checkpg(p); + } + spin_unlock(&hmc_lock); +} + diff -u -r -P 2.2.1/drivers/block/Config.in current/drivers/block/Config.in --- 2.2.1/drivers/block/Config.in Tue Dec 29 20:21:49 1998 +++ current/drivers/block/Config.in Sun Feb 7 20:37:05 1999 @@ -94,6 +94,9 @@ comment 'Additional Block Devices' tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +if [ "$CONFIG_EXPERIMENTAL" = "y" ];then + tristate 'Hugeram Ramdisk' CONFIG_BLK_DEV_HUGERAMD +fi if [ "$CONFIG_NET" = "y" ]; then tristate 'Network block device support' CONFIG_BLK_DEV_NBD fi diff -u -r -P 2.2.1/drivers/block/Makefile current/drivers/block/Makefile --- 2.2.1/drivers/block/Makefile Wed Sep 16 22:25:56 1998 +++ current/drivers/block/Makefile Sun Feb 7 20:37:05 1999 @@ -94,6 +94,14 @@ endif endif +ifeq ($(CONFIG_BLK_DEV_HUGERAMD),y) +L_OBJS += hugeramd.o +else + ifeq ($(CONFIG_BLK_DEV_HUGERAMD),m) + M_OBJS += hugeramd.o + endif +endif + ifeq ($(CONFIG_BLK_DEV_HD),y) L_OBJS += hd.o endif diff -u -r -P 2.2.1/drivers/block/hugeramd.c current/drivers/block/hugeramd.c --- 2.2.1/drivers/block/hugeramd.c Thu Jan 1 01:00:00 1970 +++ current/drivers/block/hugeramd.c Sun Feb 7 20:37:05 1999 @@ -0,0 +1,331 @@ +/* + * linux/drivers/block/hugeramd.c + * + * Written by Manfred Spraul + * + * based on the loop driver written by Theodore Ts'o + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR HUGERAMD_MAJOR +#define DEVICE_NAME "HugeRamD" +#define DEVICE_NR(device) MINOR(device) +#define DEVICE_NO_RANDOM +#define DEVICE_OFF(x) do { } while (0) +#define DEVICE_REQUEST hugeramd_request +#include + +struct HRD_DEVICE { + spinlock_t lock; + void* remap_addr; + int start; /* in pages */ + int size; + int refcount; +} ; + + +struct HRD_DEVICE hrd_devices[MAX_HUGERAMD]; + +int hugeramd_bps[MAX_HUGERAMD] = { 0}; +int hugeramd_blockcount[MAX_HUGERAMD] = {0}; +#define FALSE 0 +#define TRUE (!FALSE) + +/* + internal prototypes +*/ + +int hrd_rw(int dev, unsigned long offset, char* buf, int len, int read); + +static int hrd_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct HRD_DEVICE* hrd; + int dev; + int res; + + if (!inode) + return -EINVAL; + if (MAJOR(inode->i_rdev) != HUGERAMD_MAJOR) { + printk(KERN_WARNING "hrd_ioctl: pseudo-major != %d\n", HUGERAMD_MAJOR); + return -ENODEV; + } + dev = MINOR(inode->i_rdev); + if (dev >= MAX_HUGERAMD) + return -ENODEV; + hrd = &hrd_devices[dev]; + spin_lock(&hrd->lock); + res = 0; + switch (cmd) { + case BLKGETSIZE: /* Return device size */ + res = put_user(hrd->size<<3, (long *) arg); + break; + case HRDSETBPS: + if(!capable(CAP_SYS_ADMIN)) { + res = -EACCES; + break; + } + if( (arg != 512) && + (arg != 1024) && + (arg != 2048) && + (arg != 4096) ) { + res = -EINVAL; + break; + } + hugeramd_bps[dev] = arg; + hugeramd_blockcount[dev] = hrd->size*(PAGE_SIZE/hugeramd_bps[dev]); + break; + case HRDSETSIZE: + if(!capable(CAP_SYS_ADMIN)) { + res = -EACCES; + break; + } + if(hrd->size != 0) + { + free_hugemem(hrd->start, + hrd->size); + hrd->size = 0; + } + if(arg == 0) + break; + hrd->start = alloc_hugemem(arg); + if(hrd->start == -1) { + res = -ENOMEM; + break; + } + hrd->size = arg; + + if(hrd->remap_addr==NULL) + hrd->remap_addr = ioremap(hrd->start*PAGE_SIZE, PAGE_SIZE); + if(hrd->remap_addr == NULL) { + free_hugemem(hrd->start, + hrd->size); + hrd->size = 0; + res = -ENOMEM; + break; + } + hugeramd_blockcount[dev] = hrd->size*(PAGE_SIZE/hugeramd_bps[dev]); + break; + + /* FIXME: additional ioctl's required? */ + default: + res = -EINVAL; + } + spin_unlock(&hrd->lock); + return res; +} + +static int hrd_open(struct inode *inode, struct file *file) +{ + struct HRD_DEVICE *hrd; + int dev; + + if (!inode) + return -EINVAL; + if (MAJOR(inode->i_rdev) != HUGERAMD_MAJOR) { + printk(KERN_WARNING "hrd_open: pseudo-major != %d\n", HUGERAMD_MAJOR); + return -ENODEV; + } + dev = MINOR(inode->i_rdev); + if (dev >= MAX_HUGERAMD) { + return -ENODEV; + } + hrd = &hrd_devices[dev]; + + spin_lock(&hrd->lock); + hrd->refcount++; + spin_unlock(&hrd->lock); + MOD_INC_USE_COUNT; + return 0; +} + +static int hrd_release(struct inode *inode, struct file *file) +{ + struct HRD_DEVICE* hrd; + int dev; + + if (!inode) + return 0; + if (MAJOR(inode->i_rdev) != HUGERAMD_MAJOR) { + printk(KERN_WARNING "hrd_release: pseudo-major != %d\n", HUGERAMD_MAJOR); + return 0; + } + dev = MINOR(inode->i_rdev); + if (dev >= MAX_HUGERAMD) + return 0; + hrd = &hrd_devices[dev]; + spin_lock(&hrd->lock); + + if (hrd->refcount <= 0) + printk(KERN_ERR "hrd_release: refcount(MINOR=%d) <= 0\n", dev); + else { + hrd->refcount--; + if(hrd->refcount == 0) + MOD_DEC_USE_COUNT; + } + spin_unlock(&hrd->lock); + return 0; +} + +int hrd_fsync(struct file* unused, struct dentry* unused2) +{ + /* syncing a ramdisk??? */ + return 0; +} + +void hugeramd_request(void) +{ + int dev; + int res; + + while(1) { + INIT_REQUEST + + /* FIXME: release the io lock? */ + + dev = DEVICE_NR(CURRENT->rq_dev); + if(dev > MAX_HUGERAMD) { + res = 0; + } else + { + spin_lock(&hrd_devices[dev].lock); + res = hrd_rw(dev, CURRENT->sector, CURRENT->buffer, CURRENT->current_nr_sectors, (CURRENT->cmd != WRITE) ); + spin_unlock(&hrd_devices[dev].lock); + } + /* FIXME: reacquire the io lock ? */ + end_request(res); + } +} + +static struct file_operations hrd_fops = { + NULL, /* lseek - default */ + block_read, /* read */ + block_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* poll */ + hrd_ioctl, /* ioctl */ + NULL, /* mmap */ + hrd_open, /* open */ + NULL, /* flush */ + hrd_release, /* release */ + block_fsync /* fsync */ +}; + +/* + * And now the modules code and kernel interface. + */ +#ifdef MODULE +#define hugeramd_init init_module +#endif + +int hugeramd_init(void) +{ + int i; + + if (register_blkdev(HUGERAMD_MAJOR, "hugeramd", &hrd_fops)) { + printk(KERN_WARNING "Unable to get major number %d for hugeramd device\n", + HUGERAMD_MAJOR); + return -EIO; + } +#ifndef MODULE + printk(KERN_INFO "hugeramd: registered device at major %d\n", HUGERAMD_MAJOR); +#endif + /* FIXME: which global variables must be initialized? */ + + blksize_size[HUGERAMD_MAJOR] = hugeramd_bps; + blk_size[HUGERAMD_MAJOR] = hugeramd_blockcount; + read_ahead[HUGERAMD_MAJOR] = 0; /* no read ahead, since the seek time is 0 */ + hardsect_size[HUGERAMD_MAJOR] = NULL; + blk_dev[HUGERAMD_MAJOR].request_fn = DEVICE_REQUEST; + + for (i=0; i < MAX_HUGERAMD; i++) { + memset(&hrd_devices[i],0,sizeof(hrd_devices[i])); + hrd_devices[i].lock = SPIN_LOCK_UNLOCKED; + hugeramd_bps[i] = 1024; + hugeramd_blockcount[i] = 0; + } + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + int i; + for(i=0;i ((loff_t)hrd->size)*PAGE_SIZE) + return 0; + if(byteoff+len > ((loff_t)hrd->size)*PAGE_SIZE) + len = ((loff_t)hrd->size)*PAGE_SIZE-byteoff; + + while(len != 0) { + unsigned long linear = (unsigned long)hrd->remap_addr; + pte_t* pte = pte_offset(pmd_offset(pgd_offset_k(linear),linear), linear); + unsigned long physoffset; + int datalen; + int offset; + + physoffset = hrd->start + (byteoff>>PAGE_SHIFT); + physoffset *= PAGE_SIZE; + offset = byteoff & (PAGE_SIZE-1); + + set_pte(pte, mk_pte_phys(physoffset, __pgprot(_PAGE_PRESENT| _PAGE_RW | + _PAGE_DIRTY | _PAGE_ACCESSED ))); + + /* this call only affects the current cpu. + This is not a problem, because only one cpu is allowed to execute + these lines. + */ + __flush_tlb_one(linear); + + datalen = PAGE_SIZE-offset; + + if(datalen > len) + datalen = len; + + if(read) + memcpy(buf,(char*)linear+offset,datalen); + else + memcpy((char*)linear+offset, buf, datalen); + + buf += datalen; + len -= datalen; + byteoff += datalen; + } + + return 1; +} diff -u -r -P 2.2.1/drivers/block/ll_rw_blk.c current/drivers/block/ll_rw_blk.c --- 2.2.1/drivers/block/ll_rw_blk.c Mon Dec 28 20:19:19 1998 +++ current/drivers/block/ll_rw_blk.c Sun Feb 7 20:37:05 1999 @@ -740,6 +740,9 @@ #ifdef CONFIG_BLK_DEV_RAM rd_init(); #endif +#ifdef CONFIG_BLK_DEV_HUGERAMD + hugeramd_init(); +#endif #ifdef CONFIG_BLK_DEV_LOOP loop_init(); #endif diff -u -r -P 2.2.1/include/asm-i386/hmcache.h current/include/asm-i386/hmcache.h --- 2.2.1/include/asm-i386/hmcache.h Thu Jan 1 01:00:00 1970 +++ current/include/asm-i386/hmcache.h Mon Feb 8 19:45:41 1999 @@ -0,0 +1,16 @@ +/* + * + * (C) Manfred Spraul + * + */ + +#ifndef _HMCACHE_H +#define _HMCACHE_H + +struct page* hmc_findpage(struct inode* inode, unsigned long offset); + +void hmc_invalidate_inode_pages(struct inode* inode); +void hmc_truncate_inode_pages(struct inode* inode, unsigned long start); +void hmc_add_page(struct page* page); + +#endif /* _HMCACHE_H */ diff -u -r -P 2.2.1/include/asm-i386/hugemem.h current/include/asm-i386/hugemem.h --- 2.2.1/include/asm-i386/hugemem.h Thu Jan 1 01:00:00 1970 +++ current/include/asm-i386/hugemem.h Sun Feb 7 21:21:52 1999 @@ -0,0 +1,45 @@ +/* + * Huge memory support + * + * Copyright 1999 by Manfred Spraul + * + * 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. + * + * + */ +#ifndef _HUGEMEM_H +#define _HUGEMEM_H + +void init_hugemem(int memstart, int memend); + +/* + All size parameters are page counts. + + hugemem internally rounds all allocation + to this size. Use kmalloc if you need less + memory + */ + +#define HM_PAGES_PER_BIT 64 + +/* return value: start of the physical area, or 0 on error. */ +int alloc_hugemem(int size); + +void free_hugemem(int startpg, int size); + +/* pmax can be NULL, returns the size of the largest free area. */ +int getfree_hugemem(int* pmax); + +#endif /* _HUGEMEM_H */ diff -u -r -P 2.2.1/include/linux/hugeramd.h current/include/linux/hugeramd.h --- 2.2.1/include/linux/hugeramd.h Thu Jan 1 01:00:00 1970 +++ current/include/linux/hugeramd.h Sun Feb 7 20:37:05 1999 @@ -0,0 +1,26 @@ +#ifndef _HUGERAMD_H +#define _HUGERAMD_H + +/* + * Hugeramd: special ramdisk that uses memory from the hugeram memory pool. + * + */ + +#include + +#ifndef __i386__ +#error Hugeramd is only available on the i386 platform. +#endif + +#define HUGERAMD_MAJOR 126 /* FIXME: normal MAJOR required. */ + +#define MAX_HUGERAMD 8 /* maximum number of ramdisks. */ + +/* parameter: new page count*/ +#define HRDSETSIZE _IO(HUGERAMD_MAJOR,101) + +/* parameter: new block size */ +#define HRDSETBPS _IO(HUGERAMD_MAJOR,102) + + +#endif /* _HUGERAMD_H */ diff -u -r -P 2.2.1/include/linux/pagemap.h current/include/linux/pagemap.h --- 2.2.1/include/linux/pagemap.h Tue Jan 26 01:06:23 1999 +++ current/include/linux/pagemap.h Mon Feb 8 20:10:15 1999 @@ -44,6 +44,10 @@ #define page_hash(inode,offset) (page_hash_table+_page_hashfn(inode,offset)) +#ifdef CONFIG_HUGEMEM +extern struct page* hmc_findpage(struct inode* inode, unsigned long offset); +#endif + static inline struct page * __find_page(struct inode * inode, unsigned long offset, struct page *page) { goto inside; @@ -61,6 +65,10 @@ atomic_inc(&page->count); set_bit(PG_referenced, &page->flags); not_found: +#ifdef CONFIG_HUGEMEM + if (page == NULL) + page = hmc_findpage(inode, offset); +#endif return page; } diff -u -r -P 2.2.1/mm/filemap.c current/mm/filemap.c --- 2.2.1/mm/filemap.c Mon Jan 25 19:47:11 1999 +++ current/mm/filemap.c Mon Feb 8 20:13:21 1999 @@ -22,7 +22,9 @@ #include #include - +#ifdef __i386__ +#include +#endif /* * Shared mappings implemented 30.11.1994. It's not fully working yet, * though. @@ -65,6 +67,9 @@ __free_page(page); continue; } +#ifdef BUILD_HUGEMEM + hmc_invalidate_inode_pages(inode); +#endif } /* @@ -106,6 +111,9 @@ flush_page_to_ram(address); } } +#ifdef CONFIG_HUGEMEM + hmc_truncate_inode_pages(inode, start); +#endif } /* @@ -114,6 +122,9 @@ void remove_inode_page(struct page *page) { remove_page_from_hash_queue(page); +#ifdef CONFIG_HUGEMEM + hmc_add_page(page); +#endif remove_page_from_inode_queue(page); __free_page(page); }