⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 umem_vmm.c

📁 Simple Operating Systems (简称SOS)是一个可以运行在X86平台上(包括QEMU
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Copyright (C) 2005 David Decotigny   This program is free software; you can redistribute it and/or   modify it under the terms of the GNU General Public License   as published by the Free Software Foundation; either version 2   of the License, or (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,   USA. */#include <sos/assert.h>#include <sos/list.h>#include <sos/physmem.h>#include <sos/kmem_slab.h>#include <drivers/bochs.h>#include <hwcore/mm_context.h>#include <hwcore/paging.h>#include <drivers/zero.h>#include "umem_vmm.h"struct sos_umem_vmm_as{  /** The process that owns this address space */  struct sos_process     * process;  /** The MMU configuration of this address space */  struct sos_mm_context  * mm_context;  /** The list of VRs in this address space */  struct sos_umem_vmm_vr * list_vr;  /** Heap location */  sos_uaddr_t heap_start;  sos_size_t  heap_size; /**< Updated by sos_umem_vmm_brk() */  /* Memory usage statistics */  sos_size_t phys_total; /* shared + private */  struct vm_usage  {    sos_size_t overall;    sos_size_t ro, rw, code /* all: non readable, read and read/write */;  } vm_total, vm_shrd;  /* Page fault counters */  sos_size_t pgflt_cow;  sos_size_t pgflt_page_in;  sos_size_t pgflt_invalid;};struct sos_umem_vmm_vr{  /** The address space owning this VR */  struct sos_umem_vmm_as *address_space;  /** The location of the mapping in user space */  sos_uaddr_t start;  sos_size_t  size;  /** What accesses are allowed (read, write, exec): @see      SOS_VM_MAP_PROT_* flags in hwcore/paging.h */  sos_ui32_t  access_rights;  /** Flags of the VR. Allowed flags:   *  - SOS_VR_MAP_SHARED   */  sos_ui32_t  flags;  /**   * The callbacks for the VR called along map/unmapping of the   * resource   */  struct sos_umem_vmm_vr_ops *ops;  /** Description of the resource being mapped, if any */  struct sos_umem_vmm_mapped_resource *mapped_resource;  sos_luoffset_t offset_in_resource;  /** The VRs of an AS are linked together and are accessible by way      of as->list_vr */  struct sos_umem_vmm_vr *prev_in_as, *next_in_as;  /** The VRs mapping a given resource are linked together and are      accessible by way of mapped_resource->list_vr */  struct sos_umem_vmm_vr *prev_in_mapped_resource, *next_in_mapped_resource;};/* * We use special slab caches to allocate AS and VR data structures */static struct sos_kslab_cache * cache_of_as;static struct sos_kslab_cache * cache_of_vr;/** Temporary function to debug: list the VRs of the given As */void sos_dump_as(const struct sos_umem_vmm_as * as, const char *str){  struct sos_umem_vmm_vr *vr;  int nb_vr;  sos_bochs_printf("AS %p - %s:\n", as, str);  sos_bochs_printf("   physical mem: %x\n",		   as->phys_total);  sos_bochs_printf("   VM (all/ro+rw/exec) tot:%x/%x+%x/%x shrd:%x/%x+%x/%x\n",		   as->vm_total.overall,		   as->vm_total.ro, as->vm_total.rw, as->vm_total.code,		   as->vm_shrd.overall,		   as->vm_shrd.ro, as->vm_shrd.rw, as->vm_shrd.code);  sos_bochs_printf("   pgflt cow=%d pgin=%d inv=%d\n",		   as->pgflt_cow, as->pgflt_page_in, as->pgflt_invalid);  list_foreach_named(as->list_vr, vr, nb_vr, prev_in_as, next_in_as)    {      sos_bochs_printf("  VR[%d]=%x: [%x,%x[ (sz=%x) mr=(%x)+%llx %c%c%c fl=%x\n",		       nb_vr, (unsigned)vr,		       vr->start, vr->start + vr->size, vr->size,		       (unsigned)vr->mapped_resource,		       vr->offset_in_resource,		       (vr->access_rights & SOS_VM_MAP_PROT_READ)?'r':'-',		       (vr->access_rights & SOS_VM_MAP_PROT_WRITE)?'w':'-',		       (vr->access_rights & SOS_VM_MAP_PROT_EXEC)?'x':'-',		       (unsigned)vr->flags);    }  sos_bochs_printf("FIN (%s)\n", str);}/** * Physical address of THE page (full of 0s) used for anonymous * mappings */sos_paddr_t sos_zero_page = 0 /* Initial value prior to allocation */;/* * Helper functions defined at the bottom of the file *//** * Helper function to retrieve the first VR to have a vr->end >= uaddr */static struct sos_umem_vmm_vr *find_enclosing_or_next_vr(struct sos_umem_vmm_as * as,			  sos_uaddr_t uaddr);/** * Helper function to retrieve the first VR that overlaps the given * interval, if any */static struct sos_umem_vmm_vr *find_first_intersecting_vr(struct sos_umem_vmm_as * as,			   sos_uaddr_t start_uaddr, sos_size_t size);/** * Helper function to find first address where there is enough * space. Begin to look for such an interval at or after the given * address * * @param hint_addr The address where to begin the scan, or NULL */static sos_uaddr_tfind_first_free_interval(struct sos_umem_vmm_as * as,			 sos_uaddr_t hint_uaddr, sos_size_t size);/** Called each time a VR of the AS changes. Don't cope with any    underlying physcal mapping/unmapping, COW, etc... */static voidas_account_change_of_vr_protection(struct sos_umem_vmm_as * as,				   sos_bool_t is_shared,				   sos_size_t size,				   sos_ui32_t prev_access_rights,				   sos_ui32_t new_access_rights);sos_ret_t sos_umem_vmm_subsystem_setup(){  sos_vaddr_t vaddr_zero_page;  /* Allocate a new kernel physical page mapped into kernel space and     reset it with 0s */  vaddr_zero_page = sos_kmem_vmm_alloc(1, SOS_KMEM_VMM_MAP);  if (vaddr_zero_page == (sos_vaddr_t)NULL)    return -SOS_ENOMEM;  memset((void*)vaddr_zero_page, 0x0, SOS_PAGE_SIZE);    /* Keep a reference to the underlying pphysical page... */  sos_zero_page = sos_paging_get_paddr(vaddr_zero_page);  SOS_ASSERT_FATAL(NULL != (void*)sos_zero_page);  sos_physmem_ref_physpage_at(sos_zero_page);  /* ... but it is not needed in kernel space anymore, so we can     safely unmap it from kernel space */  sos_paging_unmap(vaddr_zero_page);  /* Allocate the VR/AS caches */  cache_of_as    = sos_kmem_cache_create("Address space structures",			    sizeof(struct sos_umem_vmm_as),			    1, 0,			    SOS_KSLAB_CREATE_MAP			    | SOS_KSLAB_CREATE_ZERO);  if (! cache_of_as)    {      sos_physmem_unref_physpage(sos_zero_page);      return -SOS_ENOMEM;    }  cache_of_vr    = sos_kmem_cache_create("Virtual Region structures",			    sizeof(struct sos_umem_vmm_vr),			    1, 0,			    SOS_KSLAB_CREATE_MAP			    | SOS_KSLAB_CREATE_ZERO);  if (! cache_of_vr)    {      sos_physmem_unref_physpage(sos_zero_page);      sos_kmem_cache_destroy(cache_of_as);      return -SOS_ENOMEM;    }  return SOS_OK;}struct sos_umem_vmm_as *sos_umem_vmm_create_empty_as(struct sos_process *owner){  struct sos_umem_vmm_as * as    = (struct sos_umem_vmm_as *) sos_kmem_cache_alloc(cache_of_as, 0);  if (! as)    return NULL;  as->mm_context = sos_mm_context_create();  if (NULL == as->mm_context)    {      /* Error */      sos_kmem_cache_free((sos_vaddr_t)as);      return NULL;    }  as->process = owner;  return as;}struct sos_umem_vmm_as *sos_umem_vmm_duplicate_current_thread_as(struct sos_process *owner){  __label__ undo_creation;  struct sos_umem_vmm_as * my_as;  struct sos_umem_vmm_vr * model_vr;  int nb_vr;  struct sos_umem_vmm_as * new_as    = (struct sos_umem_vmm_as *) sos_kmem_cache_alloc(cache_of_as, 0);  if (! new_as)    return NULL;  my_as = sos_process_get_address_space(sos_thread_get_current()->process);  new_as->process = owner;  list_init_named(new_as->list_vr, prev_in_as, next_in_as);  /*   * Switch to the current threads' mm_context, as duplicating it implies   * being able to configure some of its mappings as read-only (for   * COW)   */  SOS_ASSERT_FATAL(SOS_OK		   == sos_thread_prepare_user_space_access(my_as,							   (sos_vaddr_t)							     NULL));  /* Copy the virtual regions */  list_foreach_named(my_as->list_vr, model_vr, nb_vr, prev_in_as, next_in_as)    {      struct sos_umem_vmm_vr * vr;      /* Prepare COW on the read/write private mappings */      if ( !(model_vr->flags & SOS_VR_MAP_SHARED)	   && (model_vr->access_rights & SOS_VM_MAP_PROT_WRITE) )	{	  /* Mark the underlying physical pages (if any) as	     read-only */	  SOS_ASSERT_FATAL(SOS_OK			   == sos_paging_prepare_COW(model_vr->start,						     model_vr->size));	}      /* Allocate a new virtual region and copy the 'model' into it */      vr = (struct sos_umem_vmm_vr *) sos_kmem_cache_alloc(cache_of_vr, 0);      if (! vr)	goto undo_creation;      memcpy(vr, model_vr, sizeof(*vr));      vr->address_space = new_as;      /* Signal the "new" mapping to the underlying VR mapper */      if (vr->ops && vr->ops->ref)	vr->ops->ref(vr);      /* Insert the new VR into the new AS */      list_add_tail_named(new_as->list_vr, vr, prev_in_as, next_in_as);      /* Insert the new VR into the list of mappings of the resource */      list_add_tail_named(model_vr->mapped_resource->list_vr, vr,			  prev_in_mapped_resource,			  next_in_mapped_resource);    }  /* Now copy the current MMU configuration */  new_as->mm_context = sos_mm_context_duplicate(my_as->mm_context);  if (NULL == new_as->mm_context)    goto undo_creation;  /* Correct behavior */  new_as->heap_start = my_as->heap_start;  new_as->heap_size  = my_as->heap_size;  new_as->phys_total = my_as->phys_total;  memcpy(& new_as->vm_total, & my_as->vm_total, sizeof(struct vm_usage));  memcpy(& new_as->vm_shrd, & my_as->vm_shrd, sizeof(struct vm_usage));  SOS_ASSERT_FATAL(SOS_OK == sos_thread_end_user_space_access());  return new_as;  /* Handle erroneous behavior */ undo_creation:  SOS_ASSERT_FATAL(SOS_OK == sos_thread_end_user_space_access());  sos_umem_vmm_delete_as(new_as);  return NULL;}sos_ret_tsos_umem_vmm_delete_as(struct sos_umem_vmm_as * as){  while(! list_is_empty_named(as->list_vr, prev_in_as, next_in_as))    {      struct sos_umem_vmm_vr * vr;      vr = list_get_head_named(as->list_vr, prev_in_as, next_in_as);      /* Remove the vr from the lists */      list_pop_head_named(as->list_vr, prev_in_as, next_in_as);      list_delete_named(vr->mapped_resource->list_vr, vr,			prev_in_mapped_resource,			next_in_mapped_resource);      /* Signal to the underlying VR mapper that the mapping is	 suppressed */      if (vr->ops)	{	  if (vr->ops->unmap)	    vr->ops->unmap(vr, vr->start, vr->size);	  if (vr->ops->unref)	    vr->ops->unref(vr);	}      sos_kmem_cache_free((sos_vaddr_t)vr);    }    /* Release MMU configuration */  if (as->mm_context)    sos_mm_context_unref(as->mm_context);  /* Now unallocate main address space construct */  sos_kmem_cache_free((sos_vaddr_t)as);  return SOS_OK;}struct sos_process *sos_umem_vmm_get_process(struct sos_umem_vmm_as * as){  return as->process;}struct sos_mm_context *sos_umem_vmm_get_mm_context(struct sos_umem_vmm_as * as){  return as->mm_context;}struct sos_umem_vmm_vr *sos_umem_vmm_get_vr_at_address(struct sos_umem_vmm_as * as,			       sos_uaddr_t uaddr){  struct sos_umem_vmm_vr * vr;  vr = find_enclosing_or_next_vr(as, uaddr);  if (! vr)    return NULL;  /* Ok uaddr <= vr->end, but do we have uaddr > vr->start ? */  if (uaddr < vr->start)    return NULL;  return vr;}struct sos_umem_vmm_as *sos_umem_vmm_get_as_of_vr(struct sos_umem_vmm_vr * vr){  return vr->address_space;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -