[BACK]Return to kmem.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / mem

Diff for /prex-old/sys/mem/kmem.c between version 1.1.1.1 and 1.1.1.1.2.1

version 1.1.1.1, 2008/06/03 10:38:46 version 1.1.1.1.2.1, 2008/08/13 17:12:32
Line 32 
Line 32 
  */   */
   
 /*  /*
  * This is a memory allocator optimized for the low foot print kernel.   * This is a memory allocator optimized for the low foot print
  * It works on top of the underlying page allocator, and manages more   * kernel. It works on top of the underlying page allocator, and
  * smaller memory than page size. It will divide one page into two or   * manages more smaller memory than page size. It will divide one
  * more blocks, and each page is linked as a kernel page.   * page into two or more blocks, and each page is linked as a
    * kernel page.
  *   *
  * There are following 3 linked lists to manage used/free blocks.   * There are following 3 linked lists to manage used/free blocks.
  *  1) All pages allocated for the kernel memory are linked.   *  1) All pages allocated for the kernel memory are linked.
Line 45 
Line 46 
  * Currently, it can not handle the memory size exceeding one page.   * Currently, it can not handle the memory size exceeding one page.
  * Instead, a driver can use page_alloc() to allocate larger memory.   * Instead, a driver can use page_alloc() to allocate larger memory.
  *   *
  * The kmem functions are used by not only the kernel core but also   * The kmem functions are used by not only the kernel core but
  * by the buggy drivers. If such kernel code illegally writes data in   * also by the buggy drivers. If such kernel code illegally
  * exceeding the allocated area, the system will crash easily. In order   * writes data in exceeding the allocated area, the system will
  * to detect the memory over run, each free block has a magic ID.   * crash easily. In order to detect the memory over run, each
    * free block has a magic ID.
  */   */
   
 #include <kernel.h>  #include <kernel.h>
 #include <page.h>  #include <page.h>
 #include <sched.h>  #include <sched.h>
 #include <vm.h>  #include <vm.h>
   #include <kmem.h>
   
 /*  /*
  * Block header   * Block header
Line 72 
Line 75 
 /*  /*
  * Page header   * Page header
  *   *
  * The page header is placed at the top of each page.  This header is   * The page header is placed at the top of each page. This
  * used in order to free the page when there are no used block left in   * header is used in order to free the page when there are no
  * the page. If nr_alloc value becomes zero, that page can be removed   * used block left in the page. If nr_alloc value becomes zero,
  * from kernel page.   * that page can be removed from kernel page.
  */   */
 struct page_hdr {  struct page_hdr {
         u_short magic;                  /* magic number */          u_short magic;                  /* magic number */
Line 85 
Line 88 
   
 #define ALIGN_SIZE      16  #define ALIGN_SIZE      16
 #define ALIGN_MASK      (ALIGN_SIZE - 1)  #define ALIGN_MASK      (ALIGN_SIZE - 1)
 #define ALLOC_ALIGN(n)  (((n) + ALIGN_MASK) & ~ALIGN_MASK)  #define ALLOC_ALIGN(n)  (((vaddr_t)(n) + ALIGN_MASK) & (vaddr_t)~ALIGN_MASK)
   
 #define BLOCK_MAGIC     0xdead  #define BLOCK_MAGIC     0xdead
 #define PAGE_MAGIC      0xbeef  #define PAGE_MAGIC      0xbeef
   
 #define BLKHDR_SIZE     (sizeof(struct block_hdr))  #define BLKHDR_SIZE     (sizeof(struct block_hdr))
 #define PGHDR_SIZE      (sizeof(struct page_hdr))  #define PGHDR_SIZE      (sizeof(struct page_hdr))
 #define MAX_ALLOC_SIZE  (PAGE_SIZE - PGHDR_SIZE)  #define MAX_ALLOC_SIZE  (size_t)(PAGE_SIZE - PGHDR_SIZE)
   
 #define MIN_BLOCK_SIZE  (BLKHDR_SIZE + 16)  #define MIN_BLOCK_SIZE  (BLKHDR_SIZE + 16)
 #define MAX_BLOCK_SIZE  (u_short)(PAGE_SIZE - (PGHDR_SIZE - BLKHDR_SIZE))  #define MAX_BLOCK_SIZE  (u_short)(PAGE_SIZE - (PGHDR_SIZE - BLKHDR_SIZE))
   
 /* macro to point the page header from specific address */  /* macro to point the page header from specific address */
 #define PAGE_TOP(n)     (struct page_hdr *) \  #define PAGE_TOP(n)     (struct page_hdr *) \
                                     ((u_long)(n) & ~(PAGE_SIZE - 1))                              ((vaddr_t)(n) & (vaddr_t)~(PAGE_SIZE - 1))
   
 /* index of free block list */  /* index of free block list */
 #define BLKIDX(b)       ((int)((b)->size) >> 4)  #define BLKIDX(b)       ((u_int)((b)->size) >> 4)
   
 /* number of free block list */  /* number of free block list */
 #define NR_BLOCK_LIST   (PAGE_SIZE / ALIGN_SIZE)  #define NR_BLOCK_LIST   (PAGE_SIZE / ALIGN_SIZE)
Line 121 
Line 124 
  *     free_blocks[255] = list for 4096 byte block   *     free_blocks[255] = list for 4096 byte block
  *   *
  * Generally, only one list is used to search the free block with   * Generally, only one list is used to search the free block with
  * a first fit algorithm. Basically, this allocator also uses a first   * a first fit algorithm. Basically, this allocator also uses a
  * fit method. However it uses multiple lists corresponding to each   * first fit method. However it uses multiple lists corresponding
  * block size.   * to each block size. A search is started from the list of the
  * A search is started from the list of the requested size. So, it is   * requested size. So, it is not necessary to search smaller
  * not necessary to search smaller block's list wastefully.   * block's list wastefully.
  *   *
  * Most of kernel memory allocator is using 2^n as block size. But,   * Most of kernel memory allocator is using 2^n as block size.
  * these implementation will throw away much memory that the block   * But, these implementation will throw away much memory that
  * size is not fit. This is not suitable for the embedded system with   * the block size is not fit. This is not suitable for the
  * low foot print.   * embedded system with low foot print.
  */   */
 static struct list free_blocks[NR_BLOCK_LIST];  static struct list free_blocks[NR_BLOCK_LIST];
   
 static int kmem_bytes;          /* number of bytes currently allocated */  
   
 #ifdef DEBUG  
 /*  /*
  * profiling data  
  */  
 static int nr_pages;                    /* number of pages currently used */  
 static int nr_blocks[NR_BLOCK_LIST];    /* number of blocks currently used */  
   
 #endif  /* DEBUG */  
   
 /*  
  * Find the free block for the specified size.   * Find the free block for the specified size.
  * Returns pointer to free block, or NULL on failure.   * Returns pointer to free block, or NULL on failure.
  *   *
Line 160 
Line 152 
         int i;          int i;
         list_t n;          list_t n;
   
         for (i = (int)size >> 4; i < NR_BLOCK_LIST; i++) {          for (i = (int)((u_int)size >> 4); i < NR_BLOCK_LIST; i++) {
                 if (!list_empty(&free_blocks[i]))                  if (!list_empty(&free_blocks[i]))
                         break;                          break;
         }          }
Line 180 
Line 172 
 void *  void *
 kmem_alloc(size_t size)  kmem_alloc(size_t size)
 {  {
         struct block_hdr *blk, *new_blk;          struct block_hdr *blk, *newblk;
         struct page_hdr *pg;          struct page_hdr *pg;
         void *p;          void *p;
   
Line 216 
Line 208 
                 blk->magic = BLOCK_MAGIC;                  blk->magic = BLOCK_MAGIC;
                 blk->size = MAX_BLOCK_SIZE;                  blk->size = MAX_BLOCK_SIZE;
                 blk->pg_next = NULL;                  blk->pg_next = NULL;
 #ifdef DEBUG  
                 nr_pages++;  
 #endif  
         }          }
         /* Sanity check */          /* Sanity check */
         if (pg->magic != PAGE_MAGIC || blk->magic != BLOCK_MAGIC)          if (pg->magic != PAGE_MAGIC || blk->magic != BLOCK_MAGIC)
                 panic("kmem overrun: addr=%x", blk);                  panic("kmem_alloc: overrun");
         /*          /*
          * If the found block is large enough, split it.           * If the found block is large enough, split it.
          */           */
         if (blk->size - size >= MIN_BLOCK_SIZE) {          if (blk->size - size >= MIN_BLOCK_SIZE) {
                 /* Make new block */                  /* Make new block */
                 new_blk = (struct block_hdr *)((u_long)blk + size);                  newblk = (struct block_hdr *)((char *)blk + size);
                 new_blk->magic = BLOCK_MAGIC;                  newblk->magic = BLOCK_MAGIC;
                 new_blk->size = (u_short)(blk->size - size);                  newblk->size = (u_short)(blk->size - size);
                 list_insert(&free_blocks[BLKIDX(new_blk)], &new_blk->link);                  list_insert(&free_blocks[BLKIDX(newblk)], &newblk->link);
   
                 /* Update page list */                  /* Update page list */
                 new_blk->pg_next = blk->pg_next;                  newblk->pg_next = blk->pg_next;
                 blk->pg_next = new_blk;                  blk->pg_next = newblk;
   
                 blk->size = (u_short)size;                  blk->size = (u_short)size;
         }          }
         /* Increment allocation count of this page */          /* Increment allocation count of this page */
         pg->nallocs++;          pg->nallocs++;
         kmem_bytes += blk->size;          p = (char *)blk + BLKHDR_SIZE;
 #ifdef DEBUG  
         nr_blocks[BLKIDX(blk)]++;  
 #endif  
         p = (void *)((u_long)blk + BLKHDR_SIZE);  
         sched_unlock();          sched_unlock();
         return p;          return p;
 }  }
Line 273 
Line 258 
         sched_lock();          sched_lock();
   
         /* Get the block header */          /* Get the block header */
         blk = (struct block_hdr *)((u_long)ptr - BLKHDR_SIZE);          blk = (struct block_hdr *)((char *)ptr - BLKHDR_SIZE);
         if (blk->magic != BLOCK_MAGIC)          if (blk->magic != BLOCK_MAGIC)
                 panic("kmem_free");                  panic("kmem_free: invalid address");
   
         kmem_bytes -= blk->size;  
   
 #ifdef DEBUG  
         nr_blocks[BLKIDX(blk)]--;  
 #endif  
         /*          /*
          * Return the block to free list.           * Return the block to free list. Since kernel code will
          * Since kernel code will request fixed size of memory block,           * request fixed size of memory block, we don't merge the
          * we don't merge the blocks to use it as cache.           * blocks to use it as cache.
          */           */
         list_insert(&free_blocks[BLKIDX(blk)], &blk->link);          list_insert(&free_blocks[BLKIDX(blk)], &blk->link);
   
Line 298 
Line 278 
                  */                   */
                 for (blk = &(pg->first_blk); blk != NULL; blk = blk->pg_next) {                  for (blk = &(pg->first_blk); blk != NULL; blk = blk->pg_next) {
                         list_remove(&blk->link); /* Remove from free list */                          list_remove(&blk->link); /* Remove from free list */
 #ifdef DEBUG  
                         nr_blocks[BLKIDX(blk)]--;  
 #endif  
                 }                  }
                 pg->magic = 0;                  pg->magic = 0;
                 page_free(virt_to_phys(pg), PAGE_SIZE);                  page_free(virt_to_phys(pg), PAGE_SIZE);
 #ifdef DEBUG  
                 nr_pages--;  
 #endif  
         }          }
         sched_unlock();          sched_unlock();
 }  }
Line 325 
Line 299 
                 return NULL;                  return NULL;
         return phys_to_virt(phys);          return phys_to_virt(phys);
 }  }
   
 void  
 kmem_info(size_t *size)  
 {  
   
         *size = (size_t)kmem_bytes;  
 }  
   
 #if defined(DEBUG) && defined(CONFIG_KDUMP)  
 void  
 kmem_dump(void)  
 {  
         list_t head, n;  
         int i, cnt;  
         struct block_hdr *blk;  
   
         printk("\nKernel memory dump:\n");  
   
         printk(" allocated blocks:\n");  
         printk(" block size count\n");  
         printk(" ---------- --------\n");  
   
         for (i = 0; i < NR_BLOCK_LIST; i++) {  
                 if (nr_blocks[i])  
                         printk("       %4d %8d\n", i << 4, nr_blocks[i]);  
         }  
         printk("\n free blocks:\n");  
         printk(" block size count\n");  
         printk(" ---------- --------\n");  
   
         for (i = 0; i < NR_BLOCK_LIST; i++) {  
                 cnt = 0;  
                 head = &free_blocks[i];  
                 for (n = list_first(head); n != head; n = list_next(n)) {  
                         cnt++;  
   
                         blk = list_entry(n, struct block_hdr, link);  
                 }  
                 if (cnt > 0)  
                         printk("       %4d %8d\n", i << 4, cnt);  
         }  
         printk(" Total: page=%d (%dKbyte) alloc=%dbyte unused=%dbyte\n",  
              nr_pages, nr_pages * 4, kmem_bytes,  
              nr_pages * PAGE_SIZE - kmem_bytes);  
 }  
 #endif  
   
 void  void
 kmem_init(void)  kmem_init(void)

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.1.2.1

CVSweb