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

Diff for /prex-old/sys/mem/vm_nommu.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 28 
Line 28 
  */   */
   
 /*  /*
  * vm_nommu.c - virtual memory functions for no MMU systems   * vm_nommu.c - virtual memory alloctor for no MMU systems
  */   */
   
 /*  /*
Line 47 
Line 47 
 #include <sched.h>  #include <sched.h>
 #include <vm.h>  #include <vm.h>
   
 #ifdef CONFIG_VMTRACE  
 static void vm_error(const char *, int);  
 #define LOG(x)          printk x  
 #define CHK(fn,x)       do { if (x) vm_error(fn, x); } while (0)  
 #else  
 #define LOG(x)  
 #define CHK(fn,x)  
 #endif  
   
 /* forward declarations */  /* forward declarations */
 static struct region *region_create(struct region *, u_long, size_t);  static struct region *region_create(struct region *, void *, size_t);
 static void region_delete(struct region *, struct region *);  static void region_delete(struct region *, struct region *);
 static struct region *region_find(struct region *, u_long, size_t);  static struct region *region_find(struct region *, void *, size_t);
 static void region_free(struct region *, struct region *);  static void region_free(struct region *, struct region *);
 static void region_init(struct region *);  static void region_init(struct region *);
 static int do_allocate(vm_map_t, void **, size_t, int);  static int do_allocate(vm_map_t, void **, size_t, int);
Line 67 
Line 58 
 static int do_attribute(vm_map_t, void *, int);  static int do_attribute(vm_map_t, void *, int);
 static int do_map(vm_map_t, void *, size_t, void **);  static int do_map(vm_map_t, void *, size_t, void **);
   
   
 /* vm mapping for kernel task */  /* vm mapping for kernel task */
 static struct vm_map kern_map;  static struct vm_map kern_map;
   
 /**  /**
  * vm_allocate - allocate zero-filled memory for specified address   * vm_allocate - allocate zero-filled memory for specified address
  * @task:     task id to allocate memory  
  * @addr:     required address. set an allocated address in return.  
  * @size:     allocation size  
  * @anywhere: if it is true, the "addr" argument will be ignored.  
  *            In this case, the address of free space will be found  
  *            automatically.  
  *   *
  * The allocated area has writable, user-access attribute by default.   * If "anywhere" argument is true, the "addr" argument will be
  * The "addr" and "size" argument will be adjusted to page boundary.   * ignored.  In this case, the address of free space will be
    * found automatically.
    *
    * The allocated area has writable, user-access attribute by
    * default.  The "addr" and "size" argument will be adjusted
    * to page boundary.
  */   */
 int  int
 vm_allocate(task_t task, void **addr, size_t size, int anywhere)  vm_allocate(task_t task, void **addr, size_t size, int anywhere)
Line 88 
Line 79 
         int err;          int err;
         void *uaddr;          void *uaddr;
   
         LOG(("vm_aloc: task=%s addr=%x size=%x anywhere=%d\n",  
              task->name ? task->name : "no name", *addr, size, anywhere));  
   
         sched_lock();          sched_lock();
   
         if (!task_valid(task)) {          if (!task_valid(task)) {
                 err = ESRCH;                  err = ESRCH;
         } else if (task != cur_task() && !task_capable(CAP_MEMORY)) {                  goto out;
           }
           if (task != cur_task() && !task_capable(CAP_MEMORY)) {
                 err = EPERM;                  err = EPERM;
         } else if (umem_copyin(addr, &uaddr, sizeof(void *))) {                  goto out;
           }
           if (umem_copyin(addr, &uaddr, sizeof(void *))) {
                 err = EFAULT;                  err = EFAULT;
         } else if (anywhere == 0 && !user_area(*addr)) {                  goto out;
           }
           if (anywhere == 0 && !user_area(*addr)) {
                 err = EACCES;                  err = EACCES;
         } else {                  goto out;
                 err = do_allocate(task->map, &uaddr, size, anywhere);  
                 if (err == 0) {  
                         if (umem_copyout(&uaddr, addr, sizeof(void *)))  
                                 err = EFAULT;  
                 }  
         }          }
   
           err = do_allocate(task->map, &uaddr, size, anywhere);
           if (err == 0) {
                   if (umem_copyout(&uaddr, addr, sizeof(void *)))
                           err = EFAULT;
           }
    out:
         sched_unlock();          sched_unlock();
         CHK("vm_allocate", err);  
         return err;          return err;
 }  }
   
Line 117 
Line 112 
 do_allocate(vm_map_t map, void **addr, size_t size, int anywhere)  do_allocate(vm_map_t map, void **addr, size_t size, int anywhere)
 {  {
         struct region *reg;          struct region *reg;
         u_long start, end;          char *start, *end;
   
         if (size == 0)          if (size == 0)
                 return EINVAL;                  return EINVAL;
Line 127 
Line 122 
          */           */
         if (anywhere) {          if (anywhere) {
                 size = (size_t)PAGE_ALIGN(size);                  size = (size_t)PAGE_ALIGN(size);
                 if ((start = (u_long)page_alloc(size)) == 0)                  if ((start = page_alloc(size)) == 0)
                         return ENOMEM;                          return ENOMEM;
         } else {          } else {
                 start = PAGE_TRUNC(*addr);                  start = (char *)PAGE_TRUNC(*addr);
                 end = PAGE_ALIGN(start + size);                  end = (char *)PAGE_ALIGN(start + size);
                 size = (size_t)(end - start);                  size = (size_t)(end - start);
   
                 if (page_reserve((void *)start, size))                  if (page_reserve(start, size))
                         return EINVAL;                          return EINVAL;
         }          }
         reg = region_create(&map->head, start, size);          reg = region_create(&map->head, start, size);
         if (reg == NULL) {          if (reg == NULL) {
                 page_free((void *)start, size);                  page_free(start, size);
                 return ENOMEM;                  return ENOMEM;
         }          }
         reg->flags = REG_READ | REG_WRITE;          reg->flags = REG_READ | REG_WRITE;
   
         /* Zero fill */          /* Zero fill */
         memset((void *)start, 0, size);          memset(start, 0, size);
         *addr = (void *)reg->addr;          *addr = reg->addr;
         return 0;          return 0;
 }  }
   
Line 154 
Line 149 
  * Deallocate memory region for specified address.   * Deallocate memory region for specified address.
  *   *
  * The "addr" argument points to a memory region previously   * The "addr" argument points to a memory region previously
  * allocated through a call to vm_allocate() or vm_map(). The number   * allocated through a call to vm_allocate() or vm_map(). The
  * of bytes freed is the number of bytes of the allocated region.   * number of bytes freed is the number of bytes of the
  * If one of the region of previous and next are free, it combines   * allocated region.  If one of the region of previous and
  * with them, and larger free region is created.   * next are free, it combines with them, and larger free
    * region is created.
  */   */
 int  int
 vm_free(task_t task, void *addr)  vm_free(task_t task, void *addr)
 {  {
         int err;          int err;
   
         LOG(("vm_free: task=%s addr=%x\n",  
              task->name ? task->name : "no name", addr));  
   
         sched_lock();          sched_lock();
         if (!task_valid(task)) {          if (!task_valid(task)) {
                 err = ESRCH;                  err = ESRCH;
         } else if (task != cur_task() && !task_capable(CAP_MEMORY)) {                  goto out;
           }
           if (task != cur_task() && !task_capable(CAP_MEMORY)) {
                 err = EPERM;                  err = EPERM;
         } else if (!user_area(addr)) {                  goto out;
           }
           if (!user_area(addr)) {
                 err = EFAULT;                  err = EFAULT;
         } else {                  goto out;
                 err = do_free(task->map, addr);  
         }          }
   
           err = do_free(task->map, addr);
    out:
         sched_unlock();          sched_unlock();
         CHK("vm_free", err);  
         return err;          return err;
 }  }
   
Line 192 
Line 190 
         /*          /*
          * Find the target region.           * Find the target region.
          */           */
         reg = region_find(&map->head, (u_long)addr, 1);          reg = region_find(&map->head, addr, 1);
         if (reg == NULL || reg->addr != (u_long)addr ||          if (reg == NULL || reg->addr != addr || (reg->flags & REG_FREE))
             (reg->flags & REG_FREE))  
                 return EINVAL;  /* not allocated */                  return EINVAL;  /* not allocated */
   
         /*          /*
          * Free pages if it is not shared and mapped.           * Free pages if it is not shared and mapped.
          */           */
         if (!(reg->flags & REG_SHARED) && !(reg->flags & REG_MAPPED))          if (!(reg->flags & REG_SHARED) && !(reg->flags & REG_MAPPED))
                 page_free((void *)reg->addr, reg->size);                  page_free(reg->addr, reg->size);
   
         region_free(&map->head, reg);          region_free(&map->head, reg);
         return 0;          return 0;
Line 210 
Line 207 
 /*  /*
  * Change attribute of specified virtual address.   * Change attribute of specified virtual address.
  *   *
  * The "addr" argument points to a memory region previously allocated   * The "addr" argument points to a memory region previously
  * through a call to vm_allocate(). The attribute type can be chosen   * allocated through a call to vm_allocate(). The attribute
  * a combination of VMA_READ, VMA_WRITE.   * type can be chosen a combination of VMA_READ, VMA_WRITE.
  * Note: VMA_EXEC is not supported, yet.   * Note: VMA_EXEC is not supported, yet.
  */   */
 int  int
Line 220 
Line 217 
 {  {
         int err;          int err;
   
         LOG(("vm_attr: task=%s addr=%x attr=%x\n",  
              task->name ? task->name : "no name", addr, attr));  
   
         sched_lock();          sched_lock();
         if (attr == 0 || attr & ~(VMA_READ | VMA_WRITE)) {          if (attr == 0 || attr & ~(VMA_READ | VMA_WRITE)) {
                 err = EINVAL;                  err = EINVAL;
         } else if (!task_valid(task)) {                  goto out;
           }
           if (!task_valid(task)) {
                 err = ESRCH;                  err = ESRCH;
         } else if (task != cur_task() && !task_capable(CAP_MEMORY)) {                  goto out;
           }
           if (task != cur_task() && !task_capable(CAP_MEMORY)) {
                 err = EPERM;                  err = EPERM;
         } else if (!user_area(addr)) {                  goto out;
           }
           if (!user_area(addr)) {
                 err = EFAULT;                  err = EFAULT;
         } else {                  goto out;
                 err = do_attribute(task->map, addr, attr);  
         }          }
   
           err = do_attribute(task->map, addr, attr);
    out:
         sched_unlock();          sched_unlock();
         CHK("vm_attribute", err);  
         return err;          return err;
 }  }
   
Line 251 
Line 252 
         /*          /*
          * Find the target region.           * Find the target region.
          */           */
         reg = region_find(&map->head, (u_long)addr, 1);          reg = region_find(&map->head, addr, 1);
         if (reg == NULL || reg->addr != (u_long)addr ||          if (reg == NULL || reg->addr != addr || (reg->flags & REG_FREE)) {
             (reg->flags & REG_FREE)) {  
                 return EINVAL;  /* not allocated */                  return EINVAL;  /* not allocated */
         }          }
         /*          /*
Line 280 
Line 280 
   
 /**  /**
  * vm_map - map another task's memory to current task.   * vm_map - map another task's memory to current task.
  * @target: memory owner  
  * @addr:   target address  
  * @size:   map size  
  * @alloc:  map address returned  
  *   *
  * Note: This routine does not support mapping to the specific address.   * Note: This routine does not support mapping to the specific
    * address.
  */   */
 int  int
 vm_map(task_t target, void *addr, size_t size, void **alloc)  vm_map(task_t target, void *addr, size_t size, void **alloc)
 {  {
         int err;          int err;
   
         LOG(("vm_map : task=%s addr=%x size=%x\n",  
              target->name ? target->name : "no name", addr, size));  
   
         sched_lock();          sched_lock();
         if (!task_valid(target)) {          if (!task_valid(target)) {
                 err = ESRCH;                  err = ESRCH;
         } else if (target == cur_task()) {                  goto out;
           }
           if (target == cur_task()) {
                 err = EINVAL;                  err = EINVAL;
         } else if (!task_capable(CAP_MEMORY)) {                  goto out;
           }
           if (!task_capable(CAP_MEMORY)) {
                 err = EPERM;                  err = EPERM;
         } else if (!user_area(addr)) {                  goto out;
           }
           if (!user_area(addr)) {
                 err = EFAULT;                  err = EFAULT;
         } else {                  goto out;
                 err = do_map(target->map, addr, size, alloc);  
         }          }
   
           err = do_map(target->map, addr, size, alloc);
    out:
         sched_unlock();          sched_unlock();
         CHK("vm_map", err);  
         return err;          return err;
 }  }
   
Line 316 
Line 317 
 do_map(vm_map_t map, void *addr, size_t size, void **alloc)  do_map(vm_map_t map, void *addr, size_t size, void **alloc)
 {  {
         vm_map_t curmap;          vm_map_t curmap;
         u_long start, end;          task_t self;
           char *start, *end;
         struct region *reg, *tgt;          struct region *reg, *tgt;
         void *tmp;          void *tmp;
   
Line 328 
Line 330 
         if (umem_copyout(&tmp, alloc, sizeof(void *)))          if (umem_copyout(&tmp, alloc, sizeof(void *)))
                 return EFAULT;                  return EFAULT;
   
         start = PAGE_TRUNC(addr);          start = (char *)PAGE_TRUNC(addr);
         end = PAGE_ALIGN((u_long)addr + size);          end = (char *)PAGE_ALIGN((char *)addr + size);
         size = (size_t)(end - start);          size = (size_t)(end - start);
   
         /*          /*
Line 343 
Line 345 
         /*          /*
          * Create new region to map           * Create new region to map
          */           */
         curmap = cur_task()->map;          self = cur_task();
           curmap = self->map;
         reg = region_create(&curmap->head, start, size);          reg = region_create(&curmap->head, start, size);
         if (reg == NULL)          if (reg == NULL)
                 return ENOMEM;                  return ENOMEM;
Line 367 
Line 370 
         if ((map = kmem_alloc(sizeof(struct vm_map))) == NULL)          if ((map = kmem_alloc(sizeof(struct vm_map))) == NULL)
                 return NULL;                  return NULL;
   
         map->ref_count = 1;          map->refcnt = 1;
         region_init(&map->head);          region_init(&map->head);
         return map;          return map;
 }  }
Line 381 
Line 384 
 {  {
         struct region *reg, *tmp;          struct region *reg, *tmp;
   
         if (--map->ref_count >= 1)          if (--map->refcnt >= 1)
                 return;                  return;
   
         sched_lock();          sched_lock();
Line 391 
Line 394 
                         /* Free region if it is not shared and mapped */                          /* Free region if it is not shared and mapped */
                         if (!(reg->flags & REG_SHARED) &&                          if (!(reg->flags & REG_SHARED) &&
                             !(reg->flags & REG_MAPPED)) {                              !(reg->flags & REG_MAPPED)) {
                                 page_free((void *)reg->addr, reg->size);                                  page_free(reg->addr, reg->size);
                         }                          }
                 }                  }
                 tmp = reg;                  tmp = reg;
Line 430 
Line 433 
 vm_reference(vm_map_t map)  vm_reference(vm_map_t map)
 {  {
   
         map->ref_count++;          map->refcnt++;
         return 0;          return 0;
 }  }
   
Line 441 
Line 444 
 void *  void *
 vm_translate(void *addr, size_t size)  vm_translate(void *addr, size_t size)
 {  {
   
         return addr;          return addr;
 }  }
   
 /*  /*
  * Check if specified access can be allowed.  
  * return 0 on success, or EFAULT on failure.  
  */  
 int  
 vm_access(void *addr, size_t size, int type)  
 {  
         u_long start, end;  
         int err;  
         char tmp;  
   
         ASSERT(size);  
         start = (u_long)addr;  
         end = (u_long)addr + size - 1;  
         if ((err = umem_copyin((void *)start, &tmp, 1)))  
                 return EFAULT;  
         if (type == VMA_WRITE) {  
                 if ((err = umem_copyout(&tmp, (void *)start, 1)))  
                         return EFAULT;  
         }  
         if ((err = umem_copyin((void *)end, &tmp, 1)))  
                 return EFAULT;  
         if (type == VMA_WRITE) {  
                 if ((err = umem_copyout(&tmp, (void *)end, 1)))  
                         return EFAULT;  
         }  
         return 0;  
 }  
   
 /*  
  * Reserve specific area for boot tasks.   * Reserve specific area for boot tasks.
  */   */
 static int  static int
 do_reserve(vm_map_t map, void **addr, size_t size)  do_reserve(vm_map_t map, void **addr, size_t size)
 {  {
         struct region *reg;          struct region *reg;
         u_long start, end;          char *start, *end;
   
         if (size == 0)          if (size == 0)
                 return EINVAL;                  return EINVAL;
   
         start = PAGE_TRUNC(*addr);          start = (char *)PAGE_TRUNC(*addr);
         end = PAGE_ALIGN(start + size);          end = (char *)PAGE_ALIGN(start + size);
         size = (size_t)(end - start);          size = (size_t)(end - start);
   
         reg = region_create(&map->head, start, size);          reg = region_create(&map->head, start, size);
         if (reg == NULL)          if (reg == NULL)
                 return ENOMEM;                  return ENOMEM;
         reg->flags = REG_READ | REG_WRITE;          reg->flags = REG_READ | REG_WRITE;
         *addr = (void *)reg->addr;          *addr = reg->addr;
         return 0;          return 0;
 }  }
   
Line 505 
Line 480 
  * the proper address by a boot loader.   * the proper address by a boot loader.
  */   */
 int  int
 vm_load(vm_map_t map, struct module *m, void **stack)  vm_load(vm_map_t map, struct module *mod, void **stack)
 {  {
         void *base;          void *base;
         size_t size;          size_t size;
   
         printk("Loading task:\'%s\'\n", m->name);          DPRINTF(("Loading task:\'%s\'\n", mod->name));
   
         /*          /*
          * Reserve text & data area           * Reserve text & data area
          */           */
         base = (void *)m->text;          base = (void *)mod->text;
         size = m->textsz + m->datasz + m->bsssz;          size = mod->textsz + mod->datasz + mod->bsssz;
         if (do_reserve(map, &base, size))          if (do_reserve(map, &base, size))
                 return -1;                  return -1;
         if (m->bsssz != 0)          if (mod->bsssz != 0)
                 memset((void *)(m->data + m->datasz), 0, m->bsssz);                  memset((void *)(mod->data + mod->datasz), 0, mod->bsssz);
   
         /*          /*
          * Create stack           * Create stack
Line 535 
Line 510 
  * Returns region on success, or NULL on failure.   * Returns region on success, or NULL on failure.
  */   */
 static struct region *  static struct region *
 region_create(struct region *prev, u_long addr, size_t size)  region_create(struct region *prev, void *addr, size_t size)
 {  {
         struct region *reg;          struct region *reg;
   
Line 578 
Line 553 
  * Find the region at the specified area.   * Find the region at the specified area.
  */   */
 static struct region *  static struct region *
 region_find(struct region *head, u_long addr, size_t size)  region_find(struct region *head, void *addr, size_t size)
 {  {
         struct region *reg;          struct region *reg;
   
         reg = head;          reg = head;
         do {          do {
                 if (reg->addr <= addr &&                  if (reg->addr <= addr &&
                     reg->addr + reg->size >= addr + size) {                      (char *)reg->addr + reg->size >= (char *)addr + size) {
                         return reg;                          return reg;
                 }                  }
                 reg = reg->next;                  reg = reg->next;
Line 624 
Line 599 
   
         reg->next = reg->prev = reg;          reg->next = reg->prev = reg;
         reg->sh_next = reg->sh_prev = reg;          reg->sh_next = reg->sh_prev = reg;
         reg->addr = 0;          reg->addr = NULL;
         reg->size = 0;          reg->size = 0;
         reg->flags = REG_FREE;          reg->flags = REG_FREE;
 }  }
   
 #if defined(DEBUG) && defined(CONFIG_KDUMP)  #ifdef DEBUG
 void  static void
 vm_dump_one(task_t task)  vm_dump_one(task_t task)
 {  {
         vm_map_t map;          vm_map_t map;
         struct region *reg;          struct region *reg;
         char flags[6];          char flags[6];
         u_long total = 0;          size_t total = 0;
   
         printk("task=%x map=%x name=%s\n", task, task->map,          printf("task=%x map=%x name=%s\n", task, task->map,
                task->name ? task->name : "no name");                 task->name ? task->name : "no name");
         printk(" region   virtual  size     flags\n");          printf(" region   virtual  size     flags\n");
         printk(" -------- -------- -------- -----\n");          printf(" -------- -------- -------- -----\n");
   
         map = task->map;          map = task->map;
         reg = &map->head;          reg = &map->head;
Line 659 
Line 634 
                         if (reg->flags & REG_MAPPED)                          if (reg->flags & REG_MAPPED)
                                 flags[4] = 'M';                                  flags[4] = 'M';
   
                         printk(" %08x %08x %08x %s\n", reg,                          printf(" %08x %08x %08x %s\n", reg,
                                reg->addr, reg->size, flags);                                 reg->addr, reg->size, flags);
                         if ((reg->flags & REG_MAPPED) == 0)                          if ((reg->flags & REG_MAPPED) == 0)
                                 total += reg->size;                                  total += reg->size;
                 }                  }
                 reg = reg->next;                  reg = reg->next;
         } while (reg != &map->head);    /* Process all regions */          } while (reg != &map->head);    /* Process all regions */
         printk(" *total=%dK bytes\n\n", total / 1024);          printf(" *total=%dK bytes\n\n", total / 1024);
 }  }
   
 void  void
Line 675 
Line 650 
         list_t n;          list_t n;
         task_t task;          task_t task;
   
         printk("\nVM dump:\n");          printf("\nVM dump:\n");
         n = &kern_task.link;          n = list_first(&kern_task.link);
         do {          while (n != &kern_task.link) {
                 task = list_entry(n, struct task, link);                  task = list_entry(n, struct task, link);
                 ASSERT(task_valid(task));  
                 vm_dump_one(task);                  vm_dump_one(task);
                 n = list_next(n);                  n = list_next(n);
         } while (n != &kern_task.link);          }
 }  
 #endif  
   
   
 #ifdef CONFIG_VMTRACE  
 static void  
 vm_error(const char *func, int err)  
 {  
         printk("Error!!: %s returns err=%x\n", func, err);  
 }  }
 #endif  #endif
   

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

CVSweb