LOGIN   :::   RECOVER PASS   :::   GET ACCOUNT    
Browse
  • Projects
  • Code (CVS)
  • Forums
  • News
  • Articles
  • Polls
  •  
    OpenCores
  • FAQ
  • CVS HowTo
  • Mission
  • Media
  • Tools
  • Advertise
  • Mirrors
  • Logos
  • Contact us
  • Job Opportunity
  •  
    Tools
  • Search
      
  • Download Cores (CVSGet)
  •  
    More
  • Wishbone
  • Perlilog
  • EDA tools
  • OpenTech CD
  •  
    Navigation: All forums > Cvs-checkins > Message List > Message Post

    Message

    Reply | Reply all
    Date Prev | Date Next | Thread Prev | Thread Next Date Index | Thread Index

    From: cvs at opencores.org<cvs@o...>
    Date: Tue Dec 20 12:47:10 CET 2005
    Subject: [cvs-checkins] MODIFIED: or1k ...
    Top
    Date: 00/05/12 20:12:47

    Added: or1k/rc203soc/sw/uClinux/mmnommu Makefile filemap.c
    kmalloc.c memory.c mlock.c mmap.c mprotect.c
    mremap.c page_alloc.c swap.c swapfile.c vmalloc.c
    vmscan.c
    Log:
    First Import of RC20x uClinux


    Revision Changes Path
    1.1 or1k/rc203soc/sw/uClinux/mmnommu/Makefile

    http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/Makefile?rev=1.1&content-type=text/x-cvsweb-markup

    Index: Makefile
    ===================================================================
    #
    # Makefile for the uClinux memory manager.
    #
    # Note! Dependencies are done automagically by 'make dep', which also
    # removes any old dependencies. DON'T put your own dependencies here
    # unless it's something special (ie not a .c file).
    #
    # Note 2! The CFLAGS definition is now in the main makefile...

    O_TARGET := mm.o
    O_OBJS := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
    kmalloc.o vmalloc.o \
    swap.o vmscan.o page_alloc.o swapfile.o

    include $(TOPDIR)/Rules.make



    1.1 or1k/rc203soc/sw/uClinux/mmnommu/filemap.c

    http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/filemap.c?rev=1.1&content-type=text/x-cvsweb-markup

    Index: filemap.c
    ===================================================================
    /*
    * linux/mm/filemap.c
    *
    * Copyright (C) 1994, 1995 Linus Torvalds
    *
    * uClinux revisions
    * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>,
    * The Silver Hammer Group, Ltd.
    * Copyright (C) 1999 D. Jeff Dionne <jeff@u...>,
    * Rt-Control, Inc.
    */

    /*
    * This file handles the generic file mmap semantics used by
    * most "normal" filesystems (but you don't /have/ to use this:
    * the NFS filesystem does this differently, for example)
    */
    #include <linux/config.h> /* CONFIG_READA_SMALL */
    #include <linux/stat.h>
    #include <linux/sched.h>
    #include <linux/kernel.h>
    #include <linux/mm.h>
    #include <linux/shm.h>
    #include <linux/errno.h>
    #include <linux/mman.h>
    #include <linux/string.h>
    #include <linux/malloc.h>
    #include <linux/fs.h>
    #include <linux/locks.h>
    #include <linux/pagemap.h>
    #include <linux/swap.h>

    #include <asm/segment.h>
    #include <asm/system.h>
    #include <asm/pgtable.h>

    /*
    * Shared mappings implemented 30.11.1994. It's not fully working yet,
    * though.
    *
    * Shared mappings now work. 15.8.1995 Bruno.
    */

    unsigned long page_cache_size = 0;
    struct page * page_hash_table[PAGE_HASH_SIZE];

    /*
    * Simple routines for both non-shared and shared mappings.
    */

    #define release_page(page) __free_page((page))

    /*
    * Invalidate the pages of an inode, removing all pages that aren't
    * locked down (those are sure to be up-to-date anyway, so we shouldn't
    * invalidate them).
    */
    void invalidate_inode_pages(struct inode * inode)
    {
    struct page ** p;
    struct page * page;
    p = &inode->i_pages; while ((page = *p) != NULL) { if (PageLocked(page)) { p = &page->next; continue; } inode->i_nrpages--; if ((*p = page->next) != NULL) (*p)->prev = page->prev; page->dirty = 0; page->next = NULL; page->prev = NULL; remove_page_from_hash_queue(page); page->inode = NULL; __free_page(page); continue; } } /* * Truncate the page cache at a set offset, removing the pages * that are beyond that offset (and zeroing out partial pages). */ void truncate_inode_pages(struct inode * inode, unsigned long start) { struct page ** p; struct page * page; repeat: p = &inode->i_pages; while ((page = *p) != NULL) { unsigned long offset = page->offset; /* page wholly truncated - free it */ if (offset >= start) { if (PageLocked(page)) { __wait_on_page(page); goto repeat; } inode->i_nrpages--; if ((*p = page->next) != NULL) (*p)->prev = page->prev; page->dirty = 0; page->next = NULL; page->prev = NULL; remove_page_from_hash_queue(page); page->inode = NULL; __free_page(page); continue; } p = &page->next; offset = start - offset; /* partial truncate, clear end of page */ if (offset < PAGE_SIZE) { unsigned long address = page_address(page); memset((void *) (offset + address), 0, PAGE_SIZE - offset); flush_page_to_ram(address); } } } /* * This is called from try_to_swap_out() when we try to get rid of some * pages.. If we're unmapping the last occurrence of this page, we also * free it from the page hash-queues etc, as we don't want to keep it * in-core unnecessarily. */ unsigned long page_unuse(unsigned long page) { struct page * p = mem_map + MAP_NR(page); int count = p->count; if (count != 2) return count; if (!p->inode) return count; remove_page_from_hash_queue(p); remove_page_from_inode_queue(p); free_page(page); return 1; } /* * Update a page cache copy, when we're doing a "write()" system call * See also "update_vm_cache()". */ void update_vm_cache(struct inode * inode, unsigned long pos, const char * buf, int count) { unsigned long offset, len; offset = (pos & ~PAGE_MASK); pos = pos & PAGE_MASK; len = PAGE_SIZE - offset; do { struct page * page; if (len > count) len = count; page = find_page(inode, pos); if (page) { wait_on_page(page); memcpy((void *) (offset + page_address(page)), buf, len); release_page(page); } count -= len; buf += len; len = PAGE_SIZE; offset = 0; pos += PAGE_SIZE; } while (count); } static inline void add_to_page_cache(struct page * page, struct inode * inode, unsigned long offset, struct page **hash) { page->count++; page->flags &= ~((1 << PG_uptodate) | (1 << PG_error)); page->offset = offset; add_page_to_inode_queue(inode, page); __add_page_to_hash_queue(page, hash); } /* * Try to read ahead in the file. "page_cache" is a potentially free page * that we could use for the cache (if it is 0 we can try to create one, * this is all overlapped with the IO on the previous page finishing anyway) */ static unsigned long try_to_read_ahead(struct inode * inode, unsigned long offset, unsigned long page_cache) { struct page * page; struct page ** hash; offset &= PAGE_MASK; switch (page_cache) { case 0: page_cache = __get_free_page(GFP_KERNEL); if (!page_cache) break; default: if (offset >= inode->i_size) break; hash = page_hash(inode, offset); page = __find_page(inode, offset, *hash); if (!page) { /* * Ok, add the new page to the hash-queues... */ page = mem_map + MAP_NR(page_cache); add_to_page_cache(page, inode, offset, hash); inode->i_op->readpage(inode, page); page_cache = 0; } release_page(page); } return page_cache; } /* * Wait for IO to complete on a locked page. * * This must be called with the caller "holding" the page, * ie with increased "page->count" so that the page won't * go away during the wait.. */ void __wait_on_page(struct page *page) { struct wait_queue wait = { current, NULL }; add_wait_queue(&page->wait, &wait); repeat: run_task_queue(&tq_disk); current->state = TASK_UNINTERRUPTIBLE; if (PageLocked(page)) { schedule(); goto repeat; } remove_wait_queue(&page->wait, &wait); current->state = TASK_RUNNING; } #if 0 #define PROFILE_READAHEAD #define DEBUG_READAHEAD #endif /* * Read-ahead profiling information * -------------------------------- * Every PROFILE_MAXREADCOUNT, the following information is written * to the syslog: * Percentage of asynchronous read-ahead. * Average of read-ahead fields context value. * If DEBUG_READAHEAD is defined, a snapshot of these fields is written * to the syslog. */ #ifdef PROFILE_READAHEAD #define PROFILE_MAXREADCOUNT 1000 static unsigned long total_reada; static unsigned long total_async; static unsigned long total_ramax; static unsigned long total_ralen; static unsigned long total_rawin; static void profile_readahead(int async, struct file *filp) { unsigned long flags; ++total_reada; if (async) ++total_async; total_ramax += filp->f_ramax; total_ralen += filp->f_ralen; total_rawin += filp->f_rawin; if (total_reada > PROFILE_MAXREADCOUNT) { save_flags(flags); cli(); if (!(total_reada > PROFILE_MAXREADCOUNT)) { restore_flags(flags); return; } printk("Readahead average: max=%ld, len=%ld, win=%ld, async=%ld%%\n", total_ramax/total_reada, total_ralen/total_reada, total_rawin/total_reada, (total_async*100)/total_reada); #ifdef DEBUG_READAHEAD printk("Readahead snapshot: max=%ld, len=%ld, win=%ld, raend=%ld\n", filp->f_ramax, filp->f_ralen, filp->f_rawin, filp->f_raend); #endif total_reada = 0; total_async = 0; total_ramax = 0; total_ralen = 0; total_rawin = 0; restore_flags(flags); } } #endif /* defined PROFILE_READAHEAD */ /* * Read-ahead context: * ------------------- * The read ahead context fields of the "struct file" are the following: * - f_raend : position of the first byte after the last page we tried to * read ahead. * - f_ramax : current read-ahead maximum size. * - f_ralen : length of the current IO read block we tried to read-ahead. * - f_rawin : length of the current read-ahead window. * if last read-ahead was synchronous then * f_rawin = f_ralen * otherwise (was asynchronous) * f_rawin = previous value of f_ralen + f_ralen * * Read-ahead limits: * ------------------ * MIN_READAHEAD : minimum read-ahead size when read-ahead. * MAX_READAHEAD : maximum read-ahead size when read-ahead. * * Synchronous read-ahead benefits: * -------------------------------- * Using reasonable IO xfer length from peripheral devices increase system * performances. * Reasonable means, in this context, not too large but not too small. * The actual maximum value is: * MAX_READAHEAD + PAGE_SIZE = 76k is CONFIG_READA_SMALL is undefined * and 32K if defined (4K page size assumed). * * Asynchronous read-ahead benefits: * --------------------------------- * Overlapping next read request and user process execution increase system * performance. * * Read-ahead risks: * ----------------- * We have to guess which further data are needed by the user process. * If these data are often not really needed, it's bad for system * performances. * However, we know that files are often accessed sequentially by * application programs and it seems that it is possible to have some good * strategy in that guessing. * We only try to read-ahead files that seems to be read sequentially. * * Asynchronous read-ahead risks: * ------------------------------ * In order to maximize overlapping, we must start some asynchronous read * request from the device, as soon as possible. * We must be very careful about: * - The number of effective pending IO read requests. * ONE seems to be the only reasonable value. * - The total memory pool usage for the file access stream. * This maximum memory usage is implicitly 2 IO read chunks: * 2*(MAX_READAHEAD + PAGE_SIZE) = 156K if CONFIG_READA_SMALL is undefined, * 64k if defined (4K page size assumed). */ #define PageAlignSize(size) (((size) + PAGE_SIZE -1) & PAGE_MASK) #ifdef CONFIG_READA_SMALL /* small readahead */ #define MAX_READAHEAD PageAlignSize(4096*7) #define MIN_READAHEAD PageAlignSize(4096*2) #else /* large readahead */ #define MAX_READAHEAD PageAlignSize(4096*18) #define MIN_READAHEAD PageAlignSize(4096*3) #endif static inline unsigned long generic_file_readahead(int reada_ok, struct file * filp, struct inode * inode, unsigned long ppos, struct page * page, unsigned long page_cache) { unsigned long max_ahead, ahead; unsigned long raend; raend = filp->f_raend & PAGE_MASK; max_ahead = 0; /* * The current page is locked. * If the current position is inside the previous read IO request, do not * try to reread previously read ahead pages. * Otherwise decide or not to read ahead some pages synchronously. * If we are not going to read ahead, set the read ahead context for this * page only. */ if (PageLocked(page)) { if (!filp->f_ralen || ppos >= raend || ppos + filp->f_ralen < raend) { raend = ppos; if (raend < inode->i_size) max_ahead = filp->f_ramax; filp->f_rawin = 0; filp->f_ralen = PAGE_SIZE; if (!max_ahead) { filp->f_raend = ppos + filp->f_ralen; filp->f_rawin += filp->f_ralen; } } } /* * The current page is not locked. * If we were reading ahead and, * if the current max read ahead size is not zero and, * if the current position is inside the last read-ahead IO request, * it is the moment to try to read ahead asynchronously. * We will later force unplug device in order to force asynchronous read IO. */ else if (reada_ok && filp->f_ramax && raend >= PAGE_SIZE && ppos <= raend && ppos + filp->f_ralen >= raend) { /* * Add ONE page to max_ahead in order to try to have about the same IO max size * as synchronous read-ahead (MAX_READAHEAD + 1)*PAGE_SIZE. * Compute the position of the last page we have tried to read in order to * begin to read ahead just at the next page. */ raend -= PAGE_SIZE; if (raend < inode->i_size) max_ahead = filp->f_ramax + PAGE_SIZE; if (max_ahead) { filp->f_rawin = filp->f_ralen; filp->f_ralen = 0; reada_ok = 2; } } /* * Try to read ahead pages. * We hope that ll_rw_blk() plug/unplug, coalescence, requests sort and the * scheduler, will work enough for us to avoid too bad actuals IO requests. */ ahead = 0; while (ahead < max_ahead) { ahead += PAGE_SIZE; page_cache = try_to_read_ahead(inode, raend + ahead, page_cache); } /* * If we tried to read ahead some pages, * If we tried to read ahead asynchronously, * Try to force unplug of the device in order to start an asynchronous * read IO request. * Update the read-ahead context. * Store the length of the current read-ahead window. * Double the current max read ahead size. * That heuristic avoid to do some large IO for files that are not really * accessed sequentially. */ if (ahead) { if (reada_ok == 2) { run_task_queue(&tq_disk); } filp->f_ralen += ahead; filp->f_rawin += filp->f_ralen; filp->f_raend = raend + ahead + PAGE_SIZE; filp->f_ramax += filp->f_ramax; if (filp->f_ramax > MAX_READAHEAD) filp->f_ramax = MAX_READAHEAD; #ifdef PROFILE_READAHEAD profile_readahead((reada_ok == 2), filp); #endif } return page_cache; } /* * This is a generic file read routine, and uses the * inode->i_op->readpage() function for the actual low-level * stuff. * * This is really ugly. But the goto's actually try to clarify some * of the logic when it comes to error handling etc. */ int generic_file_read(struct inode * inode, struct file * filp, char * buf, int count) { int error, read; unsigned long pos, ppos, page_cache; int reada_ok; error = 0; read = 0; page_cache = 0; pos = filp->f_pos; ppos = pos & PAGE_MASK; #ifdef MAGIC_ROM_PTR /* Logic: if romptr f_op is available, try to get a pointer into ROM * for the data, bypassing the buffer cache entirely. This is only a * win if the ROM is reasonably fast, of course. * * Note that this path only requires that the pointer (and the data * it points to) to be valid until the memcpy_tofs is complete. * * -- Kenneth Albanowski */ if (filp->f_op->romptr) { struct vm_area_struct vma; vma.vm_start = 0; vma.vm_offset = pos; vma.vm_flags = VM_READ; if (!filp->f_op->romptr(inode, filp, &vma)) { if (count > inode->i_size - pos) count = inode->i_size - pos; memcpy_tofs(buf, (void*)vma.vm_start, count); filp->f_pos += count; return count; } } #endif /* MAGIC_ROM_PTR */ /* * If the current position is outside the previous read-ahead window, * we reset the current read-ahead context and set read ahead max to zero * (will be set to just needed value later), * otherwise, we assume that the file accesses are sequential enough to * continue read-ahead. */ if (ppos > filp->f_raend || ppos + filp->f_rawin < filp->f_raend) { reada_ok = 0; filp->f_raend = 0; filp->f_ralen = 0; filp->f_ramax = 0; filp->f_rawin = 0; } else { reada_ok = 1; } /* * Adjust the current value of read-ahead max. * If the read operation stay in the first half page, force no readahead. * Otherwise try to increase read ahead max just enough to do the read request. * Then, at least MIN_READAHEAD if read ahead is ok, * and at most MAX_READAHEAD in all cases. */ if (pos + count <= (PAGE_SIZE >> 1)) { filp->f_ramax = 0; } else { unsigned long needed; needed = ((pos + count) & PAGE_MASK) - ppos; if (filp->f_ramax < needed) filp->f_ramax = needed; if (reada_ok && filp->f_ramax < MIN_READAHEAD) filp->f_ramax = MIN_READAHEAD; if (filp->f_ramax > MAX_READAHEAD) filp->f_ramax = MAX_READAHEAD; } for (;;) { struct page *page, **hash; if (pos >= inode->i_size) break; /* * Try to find the data in the page cache.. */ hash = page_hash(inode, pos & PAGE_MASK); page = __find_page(inode, pos & PAGE_MASK, *hash); if (!page) goto no_cached_page; found_page: /* * Try to read ahead only if the current page is filled or being filled. * Otherwise, if we were reading ahead, decrease max read ahead size to * the minimum value. * In this context, that seems to may happen only on some read error or if * the page has been rewritten. */ if (PageUptodate(page) || PageLocked(page)) page_cache = generic_file_readahead(reada_ok, filp, inode, pos & PAGE_MASK, page, page_cache); else if (reada_ok && filp->f_ramax > MIN_READAHEAD) filp->f_ramax = MIN_READAHEAD; wait_on_page(page); if (!PageUptodate(page)) goto page_read_error; success: /* * Ok, we have the page, it's up-to-date and ok, * so now we can finally copy it to user space... */ { unsigned long offset, nr; offset = pos & ~PAGE_MASK; nr = PAGE_SIZE - offset; if (nr > count) nr = count; if (nr > inode->i_size - pos) nr = inode->i_size - pos; memcpy_tofs(buf, (void *) (page_address(page) + offset), nr); release_page(page); buf += nr; pos += nr; read += nr; count -= nr; if (count) { /* * to prevent hogging the CPU on well-cached systems, * schedule if needed, it's safe to do it here: */ if (need_resched) schedule(); continue; } break; } no_cached_page: /* * Ok, it wasn't cached, so we need to create a new * page.. */ if (!page_cache) { page_cache = __get_free_page(GFP_KERNEL); /* * That could have slept, so go around to the * very beginning.. */ if (page_cache) continue; error = -ENOMEM; break; } /* * Ok, add the new page to the hash-queues... */ page = mem_map + MAP_NR(page_cache); page_cache = 0; add_to_page_cache(page, inode, pos & PAGE_MASK, hash); /* * Error handling is tricky. If we get a read error, * the cached page stays in the cache (but uptodate=0), * and the next process that accesses it will try to * re-read it. This is needed for NFS etc, where the * identity of the reader can decide if we can read the * page or not.. */ /* * We have to read the page. * If we were reading ahead, we had previously tried to read this page, * That means that the page has probably been removed from the cache before * the application process needs it, or has been rewritten. * Decrease max readahead size to the minimum value in that situation. */ if (reada_ok && filp->f_ramax > MIN_READAHEAD) filp->f_ramax = MIN_READAHEAD; error = inode->i_op->readpage(inode, page); if (!error) goto found_page; release_page(page); break; page_read_error: /* * We found the page, but it wasn't up-to-date. * Try to re-read it _once_. We do this synchronously, * because this happens only if there were errors. */ error = inode->i_op->readpage(inode, page); if (!error) { wait_on_page(page); if (PageUptodate(page) && !PageError(page)) goto success; error = -EIO; /* Some unspecified error occurred.. */ } release_page(page); break; } filp->f_pos = pos; filp->f_reada = 1; if (page_cache) free_page(page_cache); UPDATE_ATIME(inode) if (!read) read = error; return read; } int shrink_mmap(int priority, int dma, int free_buf) { static int clock = 0; struct page * page; unsigned long limit = MAP_NR(high_memory); struct buffer_head *tmp, *bh; int count_max, count_min; count_max = (limit<<1) >> (priority>>1); count_min = (limit<<1) >> (priority); page = mem_map + clock; do { count_max--; if (page->inode || page->buffers) count_min--; if (PageLocked(page)) goto next; if (dma && !PageDMA(page)) goto next; /* First of all, regenerate the page's referenced bit from any buffers in the page */ bh = page->buffers; if (bh) { tmp = bh; do { if (buffer_touched(tmp)) { clear_bit(BH_Touched, &tmp->b_state); set_bit(PG_referenced, &page->flags); } tmp = tmp->b_this_page; } while (tmp != bh); } /* We can't throw away shared pages, but we do mark them as referenced. This relies on the fact that no page is currently in both the page cache and the buffer cache; we'd have to modify the following test to allow for that case. */ switch (page->count) { case 1: /* If it has been referenced recently, don't free it */ if (clear_bit(PG_referenced, &page->flags)) { /* age this page potential used */ if (priority < 4) age_page(page); break; } /* is it a page cache page? */ if (page->inode) { remove_page_from_hash_queue(page); remove_page_from_inode_queue(page); __free_page(page); return 1; } /* is it a buffer cache page? */ if (free_buf && bh && try_to_free_buffer(bh, &bh, 6)) return 1; break; default: /* more than one users: we can't throw it away */ set_bit(PG_referenced, &page->flags); /* fall through */ case 0: /* nothing */ } next: page++; clock++; if (clock >= limit) { clock = 0; page = mem_map; } } while (count_max > 0 && count_min > 0); return 0; } asmlinkage int sys_msync(unsigned long start, size_t len, int flags) { return 0; } int generic_file_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma) { return -ENOSYS; } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/kmalloc.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/kmalloc.c?rev=1.1&content-type=text/x-cvsweb-markup Index: kmalloc.c =================================================================== /* * linux/mm/kmalloc.c * * Copyright (C) 1991, 1992 Linus Torvalds & Roger Wolff. * * Written by R.E. Wolff Sept/Oct '93. * */ /* * Modified by Alex Bligh (alex@c...) 4 Apr 1994 to use multiple * pages. So for 'page' throughout, read 'area'. * * Largely rewritten.. Linus */ #include <linux/mm.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <asm/system.h> #include <asm/dma.h> /* Define this if you want slow routines that try to trip errors */ #undef SADISTIC_KMALLOC /* Private flags. */ #define MF_USED 0xffaa0055 #define MF_DMA 0xff00aa55 #define MF_FREE 0x0055ffaa /* * Much care has gone into making these routines in this file reentrant. * * The fancy bookkeeping of nbytesmalloced and the like are only used to * report them to the user (oooohhhhh, aaaaahhhhh....) are not * protected by cli(). (If that goes wrong. So what?) * * These routines restore the interrupt status to allow calling with ints * off. */ /* * A block header. This is in front of every malloc-block, whether free or not. */ struct block_header { unsigned long bh_flags; union { unsigned long ubh_length; struct block_header *fbh_next; } vp; }; #define bh_length vp.ubh_length #define bh_next vp.fbh_next #define BH(p) ((struct block_header *)(p)) /* * The page descriptor is at the front of every page that malloc has in use. */ struct page_descriptor { struct page_descriptor *next; struct block_header *firstfree; int order; int nfree; }; #define PAGE_DESC(p) ((struct page_descriptor *)(((unsigned long)(p)) & PAGE_MASK)) /* * A size descriptor describes a specific class of malloc sizes. * Each class of sizes has its own freelist. */ struct size_descriptor { struct page_descriptor *firstfree; struct page_descriptor *dmafree; /* DMA-able memory */ int nblocks; int nmallocs; int nfrees; int nbytesmalloced; int npages; unsigned long gfporder; /* number of pages in the area required */ }; /* * For now it is unsafe to allocate bucket sizes between n and * n-sizeof(page_descriptor) where n is PAGE_SIZE * any power of two * * The blocksize and sizes arrays _must_ match! */ #if PAGE_SIZE == 4096 static const unsigned int blocksize[] = { 32, 64, 128, 252, 508, 1020, 2040, 4096 - 16, 8192 - 16, 16384 - 16, 32768 - 16, 65536 - 16, 131072 - 16, 262144 - 16, #ifdef BIGALLOCS 524288 - 16, 1048576 - 16, /* SIMON: change of source file - te get mw working */ 2097152 - 16, #endif 0 }; static struct size_descriptor sizes[] = { {NULL, NULL, 127, 0, 0, 0, 0, 0}, {NULL, NULL, 63, 0, 0, 0, 0, 0}, {NULL, NULL, 31, 0, 0, 0, 0, 0}, {NULL, NULL, 16, 0, 0, 0, 0, 0}, {NULL, NULL, 8, 0, 0, 0, 0, 0}, {NULL, NULL, 4, 0, 0, 0, 0, 0}, {NULL, NULL, 2, 0, 0, 0, 0, 0}, {NULL, NULL, 1, 0, 0, 0, 0, 0}, {NULL, NULL, 1, 0, 0, 0, 0, 1}, {NULL, NULL, 1, 0, 0, 0, 0, 2}, {NULL, NULL, 1, 0, 0, 0, 0, 3}, {NULL, NULL, 1, 0, 0, 0, 0, 4}, {NULL, NULL, 1, 0, 0, 0, 0, 5}, {NULL, NULL, 1, 0, 0, 0, 0, 6}, #ifdef BIGALLOCS {NULL, NULL, 1, 0, 0, 0, 0, 7}, {NULL, NULL, 1, 0, 0, 0, 0, 8}, {NULL, NULL, 1, 0, 0, 0, 0, 9}, #endif {NULL, NULL, 0, 0, 0, 0, 0, 0}, }; #elif PAGE_SIZE == 8192 static const unsigned int blocksize[] = { 64, 128, 248, 504, 1016, 2040, 4080, 8192 - 32, 16384 - 32, 32768 - 32, 65536 - 32, 131072 - 32, 262144 - 32, 0 }; struct size_descriptor sizes[] = { {NULL, NULL, 127, 0, 0, 0, 0, 0}, {NULL, NULL, 63, 0, 0, 0, 0, 0}, {NULL, NULL, 31, 0, 0, 0, 0, 0}, {NULL, NULL, 16, 0, 0, 0, 0, 0}, {NULL, NULL, 8, 0, 0, 0, 0, 0}, {NULL, NULL, 4, 0, 0, 0, 0, 0}, {NULL, NULL, 2, 0, 0, 0, 0, 0}, {NULL, NULL, 1, 0, 0, 0, 0, 0}, {NULL, NULL, 1, 0, 0, 0, 0, 1}, {NULL, NULL, 1, 0, 0, 0, 0, 2}, {NULL, NULL, 1, 0, 0, 0, 0, 3}, {NULL, NULL, 1, 0, 0, 0, 0, 4}, {NULL, NULL, 1, 0, 0, 0, 0, 5}, {NULL, NULL, 0, 0, 0, 0, 0, 0} }; #else #error you need to make a version for your pagesize #endif #define NBLOCKS(order) (sizes[order].nblocks) #define BLOCKSIZE(order) (blocksize[order]) #define AREASIZE(order) (PAGE_SIZE<<(sizes[order].gfporder)) /* * Create a small cache of page allocations: this helps a bit with * those pesky 8kB+ allocations for NFS when we're temporarily * out of memory.. * * This is a _truly_ small cache, we just cache one single page * order (for orders 0, 1 and 2, that is 4, 8 and 16kB on x86). */ #define MAX_CACHE_ORDER 3 struct page_descriptor * kmalloc_cache[MAX_CACHE_ORDER]; static inline struct page_descriptor * get_kmalloc_pages(unsigned long priority, unsigned long order, int dma) { return (struct page_descriptor *) __get_free_pages(priority, order, dma); } static inline void free_kmalloc_pages(struct page_descriptor * page, unsigned long order, int dma) { if (!dma && order < MAX_CACHE_ORDER) { page = xchg(kmalloc_cache+order, page); if (!page) return; } free_pages((unsigned long) page, order); } long kmalloc_init(long start_mem, long end_mem) { int order; /* * Check the static info array. Things will blow up terribly if it's * incorrect. This is a late "compile time" check..... */ for (order = 0; BLOCKSIZE(order); order++) { if ((NBLOCKS(order) * BLOCKSIZE(order) + sizeof(struct page_descriptor)) > AREASIZE(order)) { printk("Cannot use %d bytes out of %d in order = %d block mallocs\n", (int) (NBLOCKS(order) * BLOCKSIZE(order) + sizeof(struct page_descriptor)), (int) AREASIZE(order), BLOCKSIZE(order)); panic("This only happens if someone messes with kmalloc"); } } return start_mem; } /* * Ugh, this is ugly, but we want the default case to run * straight through, which is why we have the ugly goto's */ void *kmalloc(size_t size, int priority) { unsigned long flags; unsigned long type; int order, dma; struct block_header *p; struct page_descriptor *page, **pg; struct size_descriptor *bucket = sizes; /* Get order */ order = 0; { unsigned int realsize = size + sizeof(struct block_header); for (;;) { int ordersize = BLOCKSIZE(order); if (realsize <= ordersize) break; order++; bucket++; if (ordersize) continue; printk("kmalloc of too large a block (%d bytes).\n", (int) size); return NULL; } } dma = 0; type = MF_USED; pg = &bucket->firstfree; if (priority & GFP_DMA) { dma = 1; type = MF_DMA; pg = &bucket->dmafree; } priority &= GFP_LEVEL_MASK; /* Sanity check... */ if (intr_count && priority != GFP_ATOMIC) { static int count = 0; if (++count < 5) { printk("kmalloc called nonatomically from interrupt %p\n", __builtin_return_address(0)); priority = GFP_ATOMIC; } } save_flags(flags); cli(); page = *pg; if (!page) goto no_bucket_page; p = page->firstfree; if (p->bh_flags != MF_FREE) goto not_free_on_freelist; found_it: page->firstfree = p->bh_next; page->nfree--; if (!page->nfree) *pg = page->next; restore_flags(flags); bucket->nmallocs++; bucket->nbytesmalloced += size; p->bh_flags = type; /* As of now this block is officially in use */ p->bh_length = size; #ifdef SADISTIC_KMALLOC memset(p+1, 0xf0, size); #endif return p + 1; /* Pointer arithmetic: increments past header */ no_bucket_page: /* * If we didn't find a page already allocated for this * bucket size, we need to get one.. * * This can be done with ints on: it is private to this invocation */ restore_flags(flags); { int i, sz; /* sz is the size of the blocks we're dealing with */ sz = BLOCKSIZE(order); page = get_kmalloc_pages(priority, bucket->gfporder, dma); if (!page) goto no_free_page; found_cached_page: bucket->npages++; page->order = order; /* Loop for all but last block: */ i = (page->nfree = bucket->nblocks) - 1; p = BH(page + 1); while (i > 0) { i--; p->bh_flags = MF_FREE; p->bh_next = BH(((long) p) + sz); p = p->bh_next; } /* Last block: */ p->bh_flags = MF_FREE; p->bh_next = NULL; p = BH(page+1); } /* * Now we're going to muck with the "global" freelist * for this size: this should be uninterruptible */ cli(); page->next = *pg; *pg = page; goto found_it; no_free_page: /* * No free pages, check the kmalloc cache of * pages to see if maybe we have something available */ if (!dma && order < MAX_CACHE_ORDER) { page = xchg(kmalloc_cache+order, page); if (page) goto found_cached_page; } { static unsigned long last = 0; if (priority != GFP_BUFFER && priority != GFP_IO && (last + 10 * HZ < jiffies)) { last = jiffies; printk("Couldn't get a free page.....\n"); } return NULL; } not_free_on_freelist: restore_flags(flags); printk("Problem: block on freelist at %08lx isn't free.\n", (long) p); return NULL; } void kfree(void *__ptr) { int dma; unsigned long flags; unsigned int order; struct page_descriptor *page, **pg; struct size_descriptor *bucket; if (!__ptr) goto null_kfree; #define ptr ((struct block_header *) __ptr) page = PAGE_DESC(ptr); __ptr = ptr - 1; if (~PAGE_MASK & (unsigned long)page->next) goto bad_order; order = page->order; if (order >= sizeof(sizes) / sizeof(sizes[0])) goto bad_order; bucket = sizes + order; dma = 0; pg = &bucket->firstfree; if (ptr->bh_flags == MF_DMA) { dma = 1; ptr->bh_flags = MF_USED; pg = &bucket->dmafree; } if (ptr->bh_flags != MF_USED) goto bad_order; ptr->bh_flags = MF_FREE; /* As of now this block is officially free */ #ifdef SADISTIC_KMALLOC memset(ptr+1, 0xe0, ptr->bh_length); #endif save_flags(flags); cli(); bucket->nfrees++; bucket->nbytesmalloced -= ptr->bh_length; ptr->bh_next = page->firstfree; page->firstfree = ptr; if (!page->nfree++) { /* Page went from full to one free block: put it on the freelist. */ if (bucket->nblocks == 1) goto free_page; page->next = *pg; *pg = page; } /* If page is completely free, free it */ if (page->nfree == bucket->nblocks) { for (;;) { struct page_descriptor *tmp = *pg; if (!tmp) goto not_on_freelist; if (tmp == page) break; pg = &tmp->next; } *pg = page->next; free_page: bucket->npages--; free_kmalloc_pages(page, bucket->gfporder, dma); } restore_flags(flags); null_kfree: return; bad_order: printk("kfree of non-kmalloced memory: %p, next= %p, order=%d\n", ptr+1, page->next, page->order); return; not_on_freelist: restore_flags(flags); printk("Ooops. page %p doesn't show on freelist.\n", page); } unsigned int ksize(void *__ptr) { unsigned int order; struct page_descriptor *page; if (!ptr) return 0; #define ptr ((struct block_header *) __ptr) page = PAGE_DESC(ptr); __ptr = ptr - 1; if (~PAGE_MASK & (unsigned long)page->next) return 0; order = page->order; if (order >= sizeof(sizes) / sizeof(sizes[0])) return 0; return BLOCKSIZE(order); } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/memory.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/memory.c?rev=1.1&content-type=text/x-cvsweb-markup Index: memory.c =================================================================== /* * linux/mm/memory.c * * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds */ /* * uClinux revisions for NO_MM * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>, * The Silver Hammer Group, Ltd. */ #include <linux/config.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/head.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/types.h> #include <linux/ptrace.h> #include <linux/mman.h> #include <linux/mm.h> #include <linux/malloc.h> #include <linux/swap.h> #include <asm/system.h> #include <asm/segment.h> #include <asm/pgtable.h> #include <asm/string.h> unsigned long high_memory = 0; mem_map_t * mem_map = NULL; /* * oom() prints a message (so that the user knows why the process died), * and gives the process an untrappable SIGKILL. */ void oom(struct task_struct * task) { printk("\nOut of memory for %s.\n", task->comm); task->sig->action[SIGKILL-1].sa_handler = NULL; task->blocked &= ~(1<<(SIGKILL-1)); send_sig(SIGKILL,task,1); } #ifdef DEBUG_VERIFY_AREA #undef verify_area int verify_area_flf(int type, const void * addr, unsigned long size, char *file, int line, char * function) { int result; result = verify_area(type, addr, size); if (result) printk("%s:%d %s> verify_area(%d,%p,%ld) = %d\n",file,line, function, type, addr, size, result); return result; } #endif /* DEBUG_VERIFY_AREA */ /* FIXME: Need to check the architecture memory map * DJD. */ int verify_area(int type, const void * addr, unsigned long size) { #ifdef CONFIG_COLDFIRE extern unsigned long _ramend; if ((unsigned long)addr > _ramend) { #else if ((unsigned long)addr > 0xf0800000) { #endif printk("Bad verify_area in process %d: %lx\n", current->pid, (unsigned long)addr); return -EFAULT; } return 0; } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/mlock.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/mlock.c?rev=1.1&content-type=text/x-cvsweb-markup Index: mlock.c =================================================================== /* * linux/mm/mlock.c * * (C) Copyright 1995 Linus Torvalds */ /* * uClinux revisions for NO_MM * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>, * The Silver Hammer Group, Ltd. * Copyright (C) 1999 D. Jeff Dionne <jeff@u...>, * Rt-Control, Inc. */ #include <linux/stat.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/shm.h> #include <linux/errno.h> #include <linux/mman.h> #include <linux/string.h> #include <linux/malloc.h> asmlinkage int sys_mlock(unsigned long start, size_t len) { return -ENOSYS; } asmlinkage int sys_munlock(unsigned long start, size_t len) { return -ENOSYS; } asmlinkage int sys_mlockall(int flags) { return -ENOSYS; } asmlinkage int sys_munlockall(void) { return -ENOSYS; } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/mmap.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/mmap.c?rev=1.1&content-type=text/x-cvsweb-markup Index: mmap.c =================================================================== /* * linux/mm/mmap.c * * Written by obz. */ /* * uClinux revisions for NO_MM * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>, * The Silver Hammer Group, Ltd. * Copyright (C) 1999 D. Jeff Dionne <jeff@u...>, * Rt-Control, Inc. */ #include <linux/stat.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/shm.h> #include <linux/errno.h> #include <linux/mman.h> #include <linux/string.h> #include <linux/malloc.h> #include <linux/pagemap.h> #include <linux/swap.h> #include <asm/segment.h> #include <asm/system.h> #include <asm/pgtable.h> /* If defined, warn whenever someone mmaps a block that has more then this number of bytes in slack space (due to kmalloc granularity). */ /*#define WARN_ON_SLACK 1024*/ /* * Combine the mmap "prot" and "flags" argument into one "vm_flags" used * internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits * into "VM_xxx". */ static inline unsigned long vm_flags(unsigned long prot, unsigned long flags) { #define _trans(x,bit1,bit2) \ ((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0) unsigned long prot_bits, flag_bits; prot_bits = _trans(prot, PROT_READ, VM_READ) | _trans(prot, PROT_WRITE, VM_WRITE) | _trans(prot, PROT_EXEC, VM_EXEC); flag_bits = _trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN) | _trans(flags, MAP_DENYWRITE, VM_DENYWRITE) | _trans(flags, MAP_EXECUTABLE, VM_EXECUTABLE); return prot_bits | flag_bits; #undef _trans } asmlinkage unsigned long sys_brk(unsigned long brk) { return -ENOSYS; } #ifdef DEBUG_MMAP #undef do_mmap unsigned long do_mmap_flf(struct file * file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long off, char*filename, int line, char*function) { unsigned long result; printk("%s @%s:%d: do_mmap by pid %d of %lu", function, filename, line, current->pid, len); result=do_mmap(file,addr,len,prot,flags,off); if (result >= -4096) /* so to speak... */ printk(" = %lx\n", result); else if (is_in_rom(result)) printk("-%lu = %lx\n", len, result); else printk("+%lu+%lu+%lu = %lx\n", ksize(result)-len, ksize(current->mm->tblock.next), ksize(current->mm->tblock.next->rblock), result); return result; } #endif /* DEBUG_MMAP */ #ifdef DEBUG static void show_process_blocks(void) { struct mm_tblock_struct * tblock, *tmp; printk("Process blocks %d:", current->pid); tmp = &current->mm->tblock; while (tmp) { printk(" %p: %p", tmp, tmp->rblock); if (tmp->rblock) printk(" (%d @%p #%d)", ksize(tmp->rblock->kblock), tmp->rblock->kblock, tmp->rblock->refcount); if (tmp->next) printk(" ->"); else printk("."); tmp = tmp->next; } printk("\n"); } #endif /* DEBUG */ extern unsigned long askedalloc, realalloc; unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long off) { void * result; struct mm_tblock_struct * tblock; if ((flags & MAP_SHARED) && (prot & PROT_WRITE) && (file)) { printk("MAP_SHARED not supported (cannot write mappings to disk)\n"); return -EINVAL; } if ((prot & PROT_WRITE) && (flags & MAP_PRIVATE)) { printk("Private writable mappings not supported\n"); return -EINVAL; } /* * determine the object being mapped and call the appropriate * specific mapper. */ if (file) { struct vm_area_struct vma; int error; if (!file->f_op) return -ENODEV; vma.vm_start = addr; vma.vm_end = addr + len; vma.vm_flags = vm_flags(prot,flags) /*| mm->def_flags*/; if (file->f_mode & 1) vma.vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; if (flags & MAP_SHARED) { vma.vm_flags |= VM_SHARED | VM_MAYSHARE; /* * This looks strange, but when we don't have the file open * for writing, we can demote the shared mapping to a simpler * private mapping. That also takes care of a security hole * with ptrace() writing to a shared mapping without write * permissions. * * We leave the VM_MAYSHARE bit on, just to get correct output * from /proc/xxx/maps.. */ if (!(file->f_mode & 2)) vma.vm_flags &= ~(VM_MAYWRITE | VM_SHARED); } vma.vm_offset = off; #ifdef MAGIC_ROM_PTR /* First, try simpler routine designed to give us a ROM pointer. */ if (file->f_op->romptr && !(prot & PROT_WRITE)) { error = file->f_op->romptr(file->f_inode, file, &vma); /*printk("romptr mmap returned %d /%x\n", error, vma.vm_start);*/ if (!error) return vma.vm_start; else if (error != -ENOSYS) return error; } else #endif /* MAGIC_ROM_PTR */ /* Then try full mmap routine, which might return a RAM pointer, or do something truly complicated. */ if (file->f_op->mmap) { error = file->f_op->mmap(file->f_inode, file, &vma); /*printk("mmap mmap returned %d /%x\n", error, vma.vm_start);*/ if (!error) return vma.vm_start; else if (error != -ENOSYS) return error; } else return -ENODEV; /* No mapping operations defined */ /* An ENOSYS error indicates that mmap isn't possible (as opposed to tried but failed) so we'll fall through to the copy. */ } tblock = (struct mm_tblock_struct *) kmalloc(sizeof(struct mm_tblock_struct), GFP_KERNEL); if (!tblock) { printk("Allocation of tblock for %lu byte allocation from process %d failed\n", len, current->pid); show_buffers(); show_free_areas(); return -ENOMEM; } tblock->rblock = (struct mm_rblock_struct *) kmalloc(sizeof(struct mm_rblock_struct), GFP_KERNEL); if (!tblock->rblock) { printk("Allocation of rblock for %lu byte allocation from process %d failed\n", len, current->pid); show_buffers(); show_free_areas(); kfree(tblock); return -ENOMEM; } result = kmalloc(len, GFP_KERNEL); if (!result) { printk("Allocation of length %lu from process %d failed\n", len, current->pid); show_buffers(); show_free_areas(); kfree(tblock->rblock); kfree(tblock); return -ENOMEM; } tblock->rblock->refcount = 1; tblock->rblock->kblock = result; tblock->rblock->size = len; realalloc += ksize(result); askedalloc += len; #ifdef WARN_ON_SLACK if ((len+WARN_ON_SLACK) <= ksize(result)) printk("Allocation of %lu bytes from process %d has %lu bytes of slack\n", len, current->pid, ksize(result)-len); #endif if (file) { int error; int old_fs = get_fs(); set_fs(KERNEL_DS); error = file->f_op->read(file->f_inode, file, (char*)result, len); set_fs(old_fs); if (error < 0) { kfree(result); kfree(tblock->rblock); kfree(tblock); return error; } if (error<len) memset(result+error, '\0', len-error); } else { memset(result, '\0', len); } realalloc += ksize(tblock); askedalloc += sizeof(struct mm_tblock_struct); realalloc += ksize(tblock->rblock); askedalloc += sizeof(struct mm_rblock_struct); tblock->next = current->mm->tblock.next; current->mm->tblock.next = tblock; #ifdef DEBUG printk("do_mmap:\n"); show_process_blocks(); #endif return (unsigned long)result; } asmlinkage int sys_munmap(unsigned long addr, size_t len) { return do_munmap(addr, len); } #ifdef DEBUG_MMAP #undef do_munmap int do_munmap_flf(unsigned long addr, size_t len, char * filename, int line, char*function) { printk("do_munmap of %lx bytes at %x invoked from %s @%s:%d\n", ksize(addr), addr, function, filename, line); return do_munmap(addr,len); } #endif /* * Munmap is split into 2 main parts -- this part which finds * what needs doing, and the areas themselves, which do the * work. This now handles partial unmappings. * Jeremy Fitzhardine <jeremy@s...> */ int do_munmap(unsigned long addr, size_t len) { struct mm_tblock_struct * tblock, *tmp; #ifdef MAGIC_ROM_PTR /* For efficiency's sake, if the pointer is obviously in ROM, don't bother walking the lists to free it */ if (is_in_rom(addr)) return 0; #endif #ifdef DEBUG printk("do_munmap:\n"); #endif tmp = &current->mm->tblock; while ((tblock=tmp->next) && (tblock->rblock) && (tblock->rblock->kblock != (void*)addr)) tmp = tblock; if (!tblock) { printk("munmap of non-mmaped memory by process %d (%s): %p\n", current->pid, current->comm, (void*)addr); return -EINVAL; } if(tblock->rblock) if(!--tblock->rblock->refcount) { if (tblock->rblock->kblock) { realalloc -= ksize(tblock->rblock->kblock); askedalloc -= tblock->rblock->size; kfree(tblock->rblock->kblock); } realalloc -= ksize(tblock->rblock); askedalloc -= sizeof(struct mm_rblock_struct); kfree(tblock->rblock); } tmp->next = tblock->next; realalloc -= ksize(tblock); askedalloc -= sizeof(struct mm_tblock_struct); kfree(tblock); #ifdef DEBUG show_process_blocks(); #endif return -EINVAL; } /* Release all mmaps. */ void exit_mmap(struct mm_struct * mm) { struct mm_tblock_struct * tmp = &mm->tblock; /*unsigned long flags;*/ if (!mm) return; if (mm->executable) iput(mm->executable); mm->executable = 0; /*save_flags(flags); cli();*/ if (mm->count > 1) { /*restore_flags(flags);*/ return; } #ifdef DEBUG printk("Exit_mmap:\n"); #endif while((tmp = tmp->next)) { if (tmp->rblock) { if (!--tmp->rblock->refcount) { if (tmp->rblock->kblock) { realalloc -= ksize(tmp->rblock->kblock); askedalloc -= tmp->rblock->size; kfree(tmp->rblock->kblock); } realalloc -= ksize(tmp->rblock); askedalloc -= sizeof(struct mm_rblock_struct); kfree(tmp->rblock); } tmp->rblock = 0; } mm->tblock.next = tmp->next; realalloc -= ksize(tmp); askedalloc -= sizeof(struct mm_tblock_struct); kfree(tmp); } #ifdef DEBUG show_process_blocks(); #endif /*restore_flags(flags);*/ } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/mprotect.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/mprotect.c?rev=1.1&content-type=text/x-cvsweb-markup Index: mprotect.c =================================================================== /* * linux/mm/mprotect.c * * (C) Copyright 1994 Linus Torvalds */ /* * uClinux revisions for NO_MM * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>, * The Silver Hammer Group, Ltd. * Copyright (C) 1999 D. Jeff Dionne <jeff@u...>, * Rt-Control, Inc. */ #include <linux/stat.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/shm.h> #include <linux/errno.h> #include <linux/mman.h> #include <linux/string.h> #include <linux/malloc.h> asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot) { return -ENOSYS; } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/mremap.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/mremap.c?rev=1.1&content-type=text/x-cvsweb-markup Index: mremap.c =================================================================== /* * linux/mm/remap.c * * (C) Copyright 1996 Linus Torvalds */ /* * uClinux revisions for NO_MM * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>, * The Silver Hammer Group, Ltd. * Copyright (C) 1999 D. Jeff Dionne <jeff@u...>, * Rt-Control, Inc. */ #include <linux/stat.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/shm.h> #include <linux/errno.h> #include <linux/mman.h> #include <linux/string.h> #include <linux/malloc.h> #include <linux/swap.h> #include <asm/segment.h> #include <asm/system.h> #include <asm/pgtable.h> /* * FIXME: Could do a tradional realloc() in some cases. */ asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags) { return -ENOSYS; } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/page_alloc.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/page_alloc.c?rev=1.1&content-type=text/x-cvsweb-markup Index: page_alloc.c =================================================================== /* * linux/mm/page_alloc.c * * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds * Swap reorganised 29.12.95, Stephen Tweedie */ /* * uClinux revisions for NO_MM * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>, * The Silver Hammer Group, Ltd. * Copyright (C) 1999 D. Jeff Dionne <jeff@u...>, * Rt-Control, Inc. */ #include <linux/config.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/head.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/stat.h> #include <linux/swap.h> #include <linux/fs.h> #include <linux/swapctl.h> #include <linux/interrupt.h> #include <asm/dma.h> #include <asm/system.h> /* for cli()/sti() */ #include <asm/segment.h> /* for memcpy_to/fromfs */ #include <asm/bitops.h> #include <asm/pgtable.h> int nr_swap_pages = 0; int nr_free_pages = 0; extern struct wait_queue *buffer_wait; /* * Free area management * * The free_area_list arrays point to the queue heads of the free areas * of different sizes */ #ifdef BIGALLOCS /* SIMON: change of source file - te get mw working */ #define NR_MEM_LISTS 10 #else #define NR_MEM_LISTS 7 #endif /* The start of this MUST match the start of "struct page" */ struct free_area_struct { struct page *next; struct page *prev; unsigned int * map; }; #define memory_head(x) ((struct page *)(x)) static struct free_area_struct free_area[NR_MEM_LISTS]; static inline void init_mem_queue(struct free_area_struct * head) { head->next = memory_head(head); head->prev = memory_head(head); } static inline void add_mem_queue(struct free_area_struct * head, struct page * entry) { struct page * next = head->next; entry->prev = memory_head(head); entry->next = next; next->prev = entry; head->next = entry; } static inline void remove_mem_queue(struct page * entry) { struct page * next = entry->next; struct page * prev = entry->prev; next->prev = prev; prev->next = next; } /* * Free_page() adds the page to the free lists. This is optimized for * fast normal cases (no error jumps taken normally). * * The way to optimize jumps for gcc-2.2.2 is to: * - select the "normal" case and put it inside the if () { XXX } * - no else-statements if you can avoid them * * With the above two rules, you get a straight-line execution path * for the normal case, giving better asm-code. * * free_page() may sleep since the page being freed may be a buffer * page or present in the swap cache. It will not sleep, however, * for a freshly allocated page (get_free_page()). */ /* * Buddy system. Hairy. You really aren't expected to understand this * * Hint: -mask = 1+~mask */ static inline void free_pages_ok(unsigned long map_nr, unsigned long order) { struct free_area_struct *area = free_area + order; unsigned long index = map_nr >> (1 + order); unsigned long mask = (~0UL) << order; unsigned long flags; save_flags(flags); cli(); #define list(x) (mem_map+(x)) map_nr &= mask; nr_free_pages -= mask; while (mask + (1 << (NR_MEM_LISTS-1))) { if (!change_bit(index, area->map)) break; remove_mem_queue(list(map_nr ^ -mask)); mask <<= 1; area++; index >>= 1; map_nr &= mask; } add_mem_queue(area, list(map_nr)); #undef list restore_flags(flags); if (!waitqueue_active(&buffer_wait)) return; wake_up(&buffer_wait); } #ifdef DEBUG_FREE_PAGES #undef __free_page void __free_page_flf(struct page *page, char*file, int line, char*function) { printk("Freeing page %p from %s @%s:%d\n", page, function, file, line); __free_page(page); } #undef free_pages void free_pages_flf(unsigned long addr, unsigned long order, char*file, int line, char*function) { printk("Freeing %lu byte page %lx from %s @%s:%d\n", 4096 << order, addr, function, file, line); free_pages(addr, order); } #undef __get_free_pages unsigned long __get_free_pages_flf(int priority, unsigned long order, int dma, char * file, int line, char * function) { printk("Allocating %d byte page from %s @%s:%d\n", 4096 << order, function, file, line); return __get_free_pages(priority, order, dma); } #undef get_free_page unsigned long get_free_page_flf(int priority, char * file, int line, char * function) { void * result = (void*)__get_free_pages_flf(priority, 0, 0, file, line, function); if (result) memset(result, 0, PAGE_SIZE); return result; } #endif /* DEBUG_FREE_PAGES */ void __free_page(struct page *page) { if (!PageReserved(page) && atomic_dec_and_test(&page->count)) { unsigned long map_nr = page->map_nr; free_pages_ok(map_nr, 0); } } void free_pages(unsigned long addr, unsigned long order) { unsigned long map_nr = MAP_NR(addr); if (map_nr < MAP_NR(high_memory)) { mem_map_t * map = mem_map + map_nr; if (PageReserved(map)) return; if (atomic_dec_and_test(&map->count)) { free_pages_ok(map_nr, order); return; } } } /* * Some ugly macros to speed up __get_free_pages().. */ #define MARK_USED(index, order, area) \ change_bit((index) >> (1+(order)), (area)->map) #define CAN_DMA(x) (PageDMA(x)) #define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT)) #define RMQUEUE(order, dma) \ do { struct free_area_struct * area = free_area+order; \ unsigned long new_order = order; \ do { struct page *prev = memory_head(area), *ret; \ while (memory_head(area) != (ret = prev->next)) { \ if (!dma || CAN_DMA(ret)) { \ unsigned long map_nr = ret->map_nr; \ (prev->next = ret->next)->prev = prev; \ MARK_USED(map_nr, new_order, area); \ nr_free_pages -= 1 << order; \ EXPAND(ret, map_nr, order, new_order, area); \ restore_flags(flags); \ return ADDRESS(map_nr); \ } \ prev = ret; \ } \ new_order++; area++; \ } while (new_order < NR_MEM_LISTS); \ } while (0) #define EXPAND(map,index,low,high,area) \ do { unsigned long size = 1 << high; \ while (high > low) { \ area--; high--; size >>= 1; \ add_mem_queue(area, map); \ MARK_USED(index, high, area); \ index += size; \ map += size; \ } \ map->count = 1; \ map->age = PAGE_INITIAL_AGE; \ } while (0) unsigned long __get_free_pages(int priority, unsigned long order, int dma) { unsigned long flags; int reserved_pages; if (order >= NR_MEM_LISTS) return 0; if (intr_count && priority != GFP_ATOMIC) { static int count = 0; if (++count < 5) { printk("gfp called nonatomically from interrupt %p\n", __builtin_return_address(0)); priority = GFP_ATOMIC; } } reserved_pages = 5; #ifndef CONFIG_REDUCED_MEMORY if (priority != GFP_NFS) reserved_pages = min_free_pages; if ((priority == GFP_BUFFER || priority == GFP_IO) && reserved_pages >= 48) reserved_pages -= (12 + (reserved_pages>>3)); #endif /* !CONFIG_REDUCED_MEMORY */ save_flags(flags); repeat: cli(); if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) { RMQUEUE(order, dma); restore_flags(flags); #ifdef DEBUG printk("fragmentation preventing allocation, re-attempting to free\n"); #endif } restore_flags(flags); if (priority != GFP_BUFFER && try_to_free_page(priority, dma, 1)) goto repeat; return 0; } /* * Show free area list (used inside shift_scroll-lock stuff) * We also calculate the percentage fragmentation. We do this by counting the * memory on each free list with the exception of the first item on the list. */ /* * That's as may be, but I added an explicit fragmentation percentage, just * to make it obvious. -kja */ /* totals held by do_mmap to compute memory wastage */ unsigned long realalloc, askedalloc; void show_free_areas(void) { unsigned long order, flags; unsigned long total = 0; unsigned long fragmented = 0; unsigned long slack; printk("Free pages: %6dkB\n ( ",nr_free_pages<<(PAGE_SHIFT-10)); save_flags(flags); cli(); for (order=0 ; order < NR_MEM_LISTS; order++) { struct page * tmp; unsigned long nr = 0; for (tmp = free_area[order].next ; tmp != memory_head(free_area+order) ; tmp = tmp->next) { nr ++; } total += nr * ((PAGE_SIZE>>10) << order); if ((nr > 1) && (order < (NR_MEM_LISTS-1))) fragmented += (nr-1) * (1 << order); printk("%lu*%lukB ", nr, (PAGE_SIZE>>10) << order); } restore_flags(flags); fragmented *= 100; fragmented /= nr_free_pages; if (realalloc) slack = (realalloc-askedalloc) * 100 / realalloc; else slack = 0; printk("= %lukB, %%%lu frag, %%%lu slack)\n", total, fragmented, slack); #ifdef SWAP_CACHE_INFO show_swap_cache_info(); #endif } #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) /* * set up the free-area data structures: * - mark all pages reserved * - mark all memory queues empty * - clear the memory bitmaps */ unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem) { mem_map_t * p; unsigned long mask = PAGE_MASK; int i; /* * select nr of pages we try to keep free for important stuff * with a minimum of 48 pages. This is totally arbitrary */ i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7); if (i < 24) i = 24; i += 24; /* The limit for buffer pages in __get_free_pages is * decreased by 12+(i>>3) */ min_free_pages = i; free_pages_low = i + (i>>1); free_pages_high = i + i; mem_map = (mem_map_t *) start_mem; p = mem_map + MAP_NR(end_mem); start_mem = LONG_ALIGN((unsigned long) p); memset(mem_map, 0, start_mem - (unsigned long) mem_map); do { --p; p->flags = (1 << PG_DMA) | (1 << PG_reserved); p->map_nr = p - mem_map; } while (p > mem_map); for (i = 0 ; i < NR_MEM_LISTS ; i++) { unsigned long bitmap_size; init_mem_queue(free_area+i); mask += mask; end_mem = (end_mem + ~mask) & mask; bitmap_size = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT + i); bitmap_size = (bitmap_size + 7) >> 3; bitmap_size = LONG_ALIGN(bitmap_size); free_area[i].map = (unsigned int *) start_mem; memset((void *) start_mem, 0, bitmap_size); start_mem += bitmap_size; } return start_mem; } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/swap.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/swap.c?rev=1.1&content-type=text/x-cvsweb-markup Index: swap.c =================================================================== /* * linux/mm/swap.c * * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds */ /* * DJD: This file should go away for uClinux... * Need to look for dependancies. */ /* * This file should contain most things doing the swapping from/to disk. * Started 18.12.91 * * Swap aging added 23.2.95, Stephen Tweedie. */ /* * uClinux revisions for NO_MM * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>, * The Silver Hammer Group, Ltd. * Copyright (C) 1999 D. Jeff Dionne <jeff@u...>, * Rt-Control, Inc. */ #include <linux/mm.h> #include <linux/sched.h> #include <linux/head.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/stat.h> #include <linux/swap.h> #include <linux/fs.h> #include <linux/swapctl.h> #include <linux/pagemap.h> #include <asm/dma.h> #include <asm/system.h> /* for cli()/sti() */ #include <asm/segment.h> /* for memcpy_to/fromfs */ #include <asm/bitops.h> #include <asm/pgtable.h> /* * We identify three levels of free memory. We never let free mem * fall below the min_free_pages except for atomic allocations. We * start background swapping if we fall below free_pages_high free * pages, and we begin intensive swapping below free_pages_low. * * Keep these three variables contiguous for sysctl(2). */ int min_free_pages = 20; int free_pages_low = 30; int free_pages_high = 40; /* We track the number of pages currently being asynchronously swapped out, so that we don't try to swap TOO many pages out at once */ atomic_t nr_async_pages = 0; /* * Constants for the page aging mechanism: the maximum age (actually, * the maximum "youthfulness"); the quanta by which pages rejuvenate * and age; and the initial age for new pages. */ swap_control_t swap_control = { 20, 3, 1, 3, /* Page aging */ 10, 2, 2, 4, /* Buffer aging */ 32, 4, /* Aging cluster */ 8192, 8192, /* Pageout and bufferout weights */ -200, /* Buffer grace */ 1, 1, /* Buffs/pages to free */ RCL_ROUND_ROBIN /* Balancing policy */ }; swapstat_t swapstats = {0}; /* General swap control */ /* Parse the kernel command line "swap=" option at load time: */ void swap_setup(char *str, int *ints) { } /* Parse the kernel command line "buff=" option at load time: */ void buff_setup(char *str, int *ints) { } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/swapfile.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/swapfile.c?rev=1.1&content-type=text/x-cvsweb-markup Index: swapfile.c =================================================================== /* * linux/mm/swapfile.c * * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds * Swap reorganised 29.12.95, Stephen Tweedie * * uClinux revisions for NO_MM * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>, * The Silver Hammer Group, Ltd. * Copyright (C) 1999 D. Jeff Dionne * Rt-Control, Inc. */ #include <linux/config.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/head.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/stat.h> #include <linux/swap.h> #include <linux/fs.h> #include <linux/swapctl.h> #include <linux/blkdev.h> /* for blk_size */ #include <linux/shm.h> /* * Compatibility functions mostly */ asmlinkage int sys_swapoff(const char * specialfile) { return -ENOSYS; } asmlinkage int sys_swapon(const char * specialfile, int swap_flags) { return -ENOSYS; } void si_swapinfo(struct sysinfo *val) { val->freeswap = val->totalswap = 0; return; } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/vmalloc.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/vmalloc.c?rev=1.1&content-type=text/x-cvsweb-markup Index: vmalloc.c =================================================================== /* * linux/mm/vmalloc.c * * Copyright (C) 1993 Linus Torvalds */ /* * uClinux revisions for NO_MM * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>, * The Silver Hammer Group, Ltd. * Copyright (C) 1999 D. Jeff Dionne <jeff@u...>, * Rt-Control, Inc. */ #include <asm/system.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/head.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/malloc.h> #include <linux/mm.h> /* * These routines just punt in a flat address space */ void vfree(void * addr) { kfree(addr); } void * vmalloc(unsigned long size) { return kmalloc(size, GFP_KERNEL); } /* * In a flat address space, there is no translation needed */ void * vremap(unsigned long offset, unsigned long size) { return (void*)offset; } int vread(char *buf, char *addr, int count) { memcpy_tofs(buf, addr, count); return count; } 1.1 or1k/rc203soc/sw/uClinux/mmnommu/vmscan.c http://www.opencores.org/cvsweb.shtml/or1k/rc203soc/sw/uClinux/mmnommu/vmscan.c?rev=1.1&content-type=text/x-cvsweb-markup Index: vmscan.c =================================================================== /* * linux/mm/vmscan.c * * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds * * Swap reorganised 29.12.95, Stephen Tweedie. * kswapd added: 7.1.96 sct * Version: $Id: vmscan.c,v 1.1 2005/12/20 11:47:06 jcastillo Exp $ */ /* * uClinux revisions for NO_MM * Copyright (C) 1998 Kenneth Albanowski <kjahds@k...>, * The Silver Hammer Group, Ltd. * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@u...>, * Rt-Control, Inc. */ #include <linux/mm.h> #include <linux/sched.h> #include <linux/head.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/stat.h> #include <linux/swap.h> #include <linux/fs.h> #include <linux/swapctl.h> #include <linux/pagemap.h> #include <linux/smp_lock.h> /* * We can't swap, so all we can do is shrink mmap. */ int try_to_free_page(int priority, int dma, int wait) { int i=6; int stop, can_do_io; #ifdef DEBUG printk("trying to find free page within pid %d...\n", current->pid); #endif /* we don't try as hard if we're not waiting.. */ stop = 3; can_do_io = 1; if (wait) stop = 0; if (priority == GFP_IO) can_do_io = 0; do { #ifdef DEBUG printk("Attempting to shrink_mmap\n"); #endif if (shrink_mmap(i, dma, can_do_io)) return 1; i--; } while ((i - stop) >= 0); printk("Failed to free page\n"); return 0; } /* * In case someone wants to re-implement swapping... */ void init_swap_timer(void) { }

     
    Copyright (c) 1999 OPENCORES.ORG. All rights reserved.