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

📄 umem_vmm.c

📁 Simple Operating Systems (简称SOS)是一个可以运行在X86平台上(包括QEMU
💻 C
📖 第 1 页 / 共 4 页
字号:
	  vr->offset_in_resource += translation;	  vr->start              += translation;	  	  /* Signal unmapping */	  if (vr->ops && vr->ops->unmap)	    vr->ops->unmap(vr, uaddr + size,			   translation);	  	  /* Account for change in VRs */	  as_account_change_of_vr_protection(as, vr->flags & SOS_VR_MAP_SHARED,					     translation,					     vr->access_rights, 0);	  /* No need to go further, we reached the last VR that	     overlaps the unmapped region */	  break;	}      /* Unmapped region only affects the ENDING address of the VR */      else if (uaddr + size >= vr->start + vr->size)	{	  sos_size_t unmapped_size = vr->start + vr->size - uaddr;	  /* Resize VR */	  vr->size = uaddr - vr->start;	  	  /* Signal unmapping */	  if (vr->ops && vr->ops->unmap)	    vr->ops->unmap(vr, uaddr, unmapped_size);	  /* Account for change in VRs */	  as_account_change_of_vr_protection(as, vr->flags & SOS_VR_MAP_SHARED,					     unmapped_size,					     vr->access_rights, 0);	  	  vr = vr->next_in_as;	  continue;	}      sos_display_fatal_error("BUG uaddr=%x sz=%x vr_start=%x, vr_sz=%x",			      uaddr, size, vr->start, vr->size);    }  need_to_setup_mmu = (sos_thread_get_current()->squatted_mm_context		       != as->mm_context);  if (need_to_setup_mmu)    SOS_ASSERT_FATAL(SOS_OK		     == sos_thread_prepare_user_space_access(as,							     (sos_vaddr_t)							       NULL));  {    sos_size_t sz_unmapped = sos_paging_unmap_interval(uaddr, size);    SOS_ASSERT_FATAL(sz_unmapped >= 0);    as->phys_total -= sz_unmapped;  }  if (need_to_setup_mmu)    SOS_ASSERT_FATAL(SOS_OK == sos_thread_end_user_space_access());  if (! used_preallocated_vr)    sos_kmem_vmm_free((sos_vaddr_t)preallocated_vr);  return SOS_OK;}sos_ret_tsos_umem_vmm_chprot(struct sos_umem_vmm_as * as,		    sos_uaddr_t uaddr, sos_size_t size,		    sos_ui32_t new_access_rights){  struct sos_umem_vmm_vr *start_vr, *vr,    *preallocated_middle_vr, *preallocated_right_vr;  sos_bool_t used_preallocated_middle_vr, used_preallocated_right_vr;  if (! SOS_IS_PAGE_ALIGNED(uaddr))    return -SOS_EINVAL;  if (size <= 0)    return -SOS_EINVAL;  size = SOS_PAGE_ALIGN_SUP(size);  /* Make sure the uaddr is valid */  if (uaddr < SOS_PAGING_BASE_USER_ADDRESS)    return -SOS_EINVAL;  if (uaddr > SOS_PAGING_TOP_USER_ADDRESS - size)    return -SOS_EINVAL;  /* Pre-allocate 2 new VRs (same reason as for unmap). Because chprot     may imply at most 2 regions to be split */  used_preallocated_middle_vr = FALSE;  used_preallocated_right_vr  = FALSE;  preallocated_middle_vr    = (struct sos_umem_vmm_vr *)sos_kmem_cache_alloc(cache_of_vr, 0);  if (! preallocated_middle_vr)    return -SOS_ENOMEM;  preallocated_right_vr    = (struct sos_umem_vmm_vr *)sos_kmem_cache_alloc(cache_of_vr, 0);  if (! preallocated_right_vr)    {      sos_kmem_vmm_free((sos_vaddr_t)preallocated_middle_vr);      return -SOS_ENOMEM;    }  /* Find any VR intersecting with the given interval */  start_vr = find_first_intersecting_vr(as, uaddr, size);  if (NULL == start_vr)    return SOS_OK;  /* First of all: make sure we are allowed to change the access     rights of all the VRs concerned by the chprot */  vr = start_vr;  while (TRUE)    {      /* Went past the end of the *circular* list => back at the	 begining ? */      if (vr->start + vr->size <= uaddr)	/* Yes, stop now */	break;      /* Went beyond the region to chprot ? */      if (uaddr + size < vr->start)	/* Yes, stop now */	break;      if (vr->flags & SOS_VR_MAP_SHARED)	{	  /* Make sure the mapped resource allows the required	     protection flags */	  if ( ( (new_access_rights & SOS_VM_MAP_PROT_READ)		 && !(vr->mapped_resource->allowed_access_rights		      & SOS_VM_MAP_PROT_READ) )	       || ( (new_access_rights & SOS_VM_MAP_PROT_WRITE)		    && !(vr->mapped_resource->allowed_access_rights			 & SOS_VM_MAP_PROT_WRITE) )	       || ( (new_access_rights & SOS_VM_MAP_PROT_EXEC)		    && !(vr->mapped_resource->allowed_access_rights			 & SOS_VM_MAP_PROT_EXEC) ) )	    return -SOS_EPERM;	}      vr = vr->next_in_as;    }  /* Change the access rights of the VRs covered by [uaddr     .. uaddr+size[ */  vr = start_vr;  while (TRUE)    {      /* Went past the end of the *circular* list => back at the	 begining ? */      if (vr->start + vr->size <= uaddr)	/* Yes, stop now */	break;      /* Went beyond the region to chprot ? */      if (uaddr + size <= vr->start)	/* Yes, stop now */	break;      /* Access rights unchanged ? */      if (vr->access_rights == new_access_rights)	/* nop */	{	  vr = vr->next_in_as;	  continue;	}      /* VR totally chprot ? */      if ((vr->start >= uaddr)	  && (vr->start + vr->size <= uaddr + size))	{	  /* Account for change in VRs */	  as_account_change_of_vr_protection(as, vr->flags & SOS_VR_MAP_SHARED,					     vr->size, vr->access_rights,					     new_access_rights);	  vr->access_rights = new_access_rights;	  if (vr->flags & SOS_VR_MAP_SHARED)	    /* For shared mappings: effectively change the access	       rights of the physical pages  */	    sos_paging_set_prot_of_interval(vr->start, vr->size,					    new_access_rights);	  else	    /* Private mapping */	    {	      /* For private mappings, we set the new access_rights		 only if it becomes read-only. For private mappings		 that become writable, we don't do anything: we keep		 the access rights unchanged to preserve the COW		 semantics */	      if (! (new_access_rights & SOS_VM_MAP_PROT_WRITE))		sos_paging_set_prot_of_interval(vr->start, vr->size,						new_access_rights);	    }	  vr = vr->next_in_as;	  continue;	}      /* chprot region lies completely INSIDE the VR */      else if ( (vr->start < uaddr)		&& (vr->start + vr->size > uaddr + size) )	{	  /* VR has to be split into 3 */	  /* Use the preallocated VRs and copy the VR into them */	  SOS_ASSERT_FATAL(! used_preallocated_middle_vr);	  SOS_ASSERT_FATAL(! used_preallocated_right_vr);	  used_preallocated_middle_vr = TRUE;	  memcpy(preallocated_middle_vr, vr, sizeof(*vr));	  used_preallocated_right_vr = TRUE;	  memcpy(preallocated_right_vr, vr, sizeof(*vr));	  /* Adjust the start/size of the VRs */	  preallocated_middle_vr->start = uaddr;	  preallocated_middle_vr->size  = size;	  preallocated_right_vr->start  = uaddr + size;	  preallocated_right_vr->size   = vr->start + vr->size	                                    - (uaddr + size);	  preallocated_middle_vr->offset_in_resource	    += uaddr - vr->start;	  preallocated_right_vr->offset_in_resource	    += uaddr + size - vr->start;	  vr->size = uaddr - vr->start;	  /* Account for change in VRs */	  preallocated_middle_vr->access_rights = new_access_rights;	  as_account_change_of_vr_protection(as, vr->flags & SOS_VR_MAP_SHARED,					     size, vr->access_rights,					     new_access_rights);	  /* Insert the new VRs into the lists */	  list_insert_after_named(as->list_vr, vr, preallocated_middle_vr,				  prev_in_as, next_in_as);	  list_insert_after_named(as->list_vr, preallocated_middle_vr,				  preallocated_right_vr,				  prev_in_as, next_in_as);	  list_add_tail_named(vr->mapped_resource->list_vr,			      preallocated_middle_vr,			      prev_in_mapped_resource,			      next_in_mapped_resource);	  list_add_tail_named(vr->mapped_resource->list_vr,			      preallocated_right_vr,			      prev_in_mapped_resource,			      next_in_mapped_resource);	  /* Effectively change the access rights of the physical pages */	  if (!(preallocated_middle_vr->flags & SOS_VR_MAP_SHARED)	      && (new_access_rights & SOS_VM_MAP_PROT_WRITE))	    /* For private mappings with write access, prepare for COW */	    sos_paging_prepare_COW(preallocated_middle_vr->start,				   preallocated_middle_vr->size);	  else	    sos_paging_set_prot_of_interval(preallocated_middle_vr->start,					    preallocated_middle_vr->size,					    new_access_rights);	  if (preallocated_right_vr->ops && preallocated_right_vr->ops->ref)	    preallocated_right_vr->ops->ref(preallocated_right_vr);	  if (preallocated_middle_vr->ops && preallocated_middle_vr->ops->ref)	    preallocated_middle_vr->ops->ref(preallocated_middle_vr);	  /* No need to go further */	  break;	}      /* Chprot region only affects the START address of the VR */      else if (uaddr <= vr->start)	{	  /* Split the region into 2 */	  sos_uoffset_t offset_in_region = uaddr + size - vr->start;	  /* Use the preallocated VRs and copy the VR into them */	  SOS_ASSERT_FATAL(! used_preallocated_middle_vr);	  used_preallocated_middle_vr = TRUE;	  memcpy(preallocated_middle_vr, vr, sizeof(*vr));	  /* Adjust the start/size of the VRs */	  preallocated_middle_vr->start += offset_in_region;	  preallocated_middle_vr->size  -= offset_in_region;	  vr->size                       = offset_in_region;	  preallocated_middle_vr->offset_in_resource += offset_in_region;	  /* Account for change in VRs */	  as_account_change_of_vr_protection(as, vr->flags & SOS_VR_MAP_SHARED,					     vr->size,					     vr->access_rights,					     new_access_rights);	  vr->access_rights = new_access_rights;	  /* Insert the new VR into the lists */	  list_insert_after_named(as->list_vr, vr,				  preallocated_middle_vr,				  prev_in_as, next_in_as);	  list_add_tail_named(vr->mapped_resource->list_vr,			      preallocated_middle_vr,			      prev_in_mapped_resource,			      next_in_mapped_resource);	  /* Effectively change the access rights of the physical pages */	  if (!(vr->flags & SOS_VR_MAP_SHARED)	      && (new_access_rights & SOS_VM_MAP_PROT_WRITE))	    /* For private mappings with write access, prepare for COW */	    sos_paging_prepare_COW(vr->start, vr->size);	  else	    sos_paging_set_prot_of_interval(vr->start, vr->size,					    new_access_rights);	  if (preallocated_middle_vr->ops && preallocated_middle_vr->ops->ref)	    preallocated_middle_vr->ops->ref(preallocated_middle_vr);	  /* Ne need to go further (we reached the last VR that	     overlaps the given interval to chprot) */	  break;	}      /* Chprot region only affects the ENDING address of the VR */      else if (uaddr + size >= vr->start + vr->size)	{	  /* Split the region into 2 */	  sos_uoffset_t offset_in_region = uaddr - vr->start;	  /* Use the preallocated VRs and copy the VR into them */	  SOS_ASSERT_FATAL(! used_preallocated_right_vr);	  used_preallocated_right_vr = TRUE;	  memcpy(preallocated_right_vr, vr, sizeof(*vr));	  /* Adjust the start/size of the VRs */	  preallocated_right_vr->start        += offset_in_region;	  preallocated_right_vr->size         -= offset_in_region;	  vr->size                             = offset_in_region;	  preallocated_right_vr->offset_in_resource += offset_in_region;	  /* Account for change in VRs */	  as_account_change_of_vr_protection(as, vr->flags & SOS_VR_MAP_SHARED,					     preallocated_right_vr->size,					     vr->access_rights,					     new_access_rights);	  preallocated_right_vr->access_rights = new_access_rights;	  /* Insert the new VR into the lists */	  list_insert_after_named(as->list_vr, vr,				  preallocated_right_vr,				  prev_in_as, next_in_as);	  list_add_tail_named(vr->mapped_resource->list_vr,			      preallocated_right_vr,			      prev_in_mapped_resource,			      next_in_mapped_resource);	  /* Effectively change the access rights of the physical pages */	  if (!(preallocated_right_vr->flags & SOS_VR_MAP_SHARED)	      && (new_access_rights & SOS_VM_MAP_PROT_WRITE))	    /* For private mappings with write access, prepare for COW */	    sos_paging_prepare_COW(preallocated_right_vr->start,				   preallocated_right_vr->size);	  else	    sos_paging_set_prot_of_interval(preallocated_right_vr->start,					    preallocated_right_vr->size,					    new_access_rights);	  if (preallocated_right_vr->ops && preallocated_right_vr->ops->ref)	    preallocated_right_vr->ops->ref(preallocated_right_vr);	  vr = vr->next_in_as;	  continue;	}      sos_display_fatal_error("BUG");    }  if (! used_preallocated_middle_vr)    sos_kmem_vmm_free((sos_vaddr_t)preallocated_middle_vr);  if (! used_preallocated_right_vr)    sos_kmem_vmm_free((sos_vaddr_t)preallocated_right_vr);  return SOS_OK;}sos_ret_tsos_umem_vmm_resize(struct sos_umem_vmm_as * as,		    sos_uaddr_t old_uaddr, sos_size_t old_size,		    sos_uaddr_t *new_uaddr, sos_size_t new_size,		    sos_ui32_t flags){  sos_luoffset_t new_offset_in_resource;  sos_bool_t must_move_vr = FALSE;  struct sos_umem_vmm_vr *vr, *prev_vr, *next_vr;  /* Make sure the new uaddr is valid */  if (*new_uaddr < SOS_PAGING_BASE_USER_ADDRESS)    return -SOS_EINVAL;  if (*new_uaddr > SOS_PAGING_TOP_USER_ADDRESS - new_size)    return -SOS_EINVAL;  old_uaddr = SOS_PAGE_ALIGN_INF(old_uaddr);  old_size  = SOS_PAGE_ALIGN_SUP(old_size);  if (! SOS_IS_PAGE_ALIGNED(*new_uaddr))    return -SOS_EINVAL;  if (new_size <= 0)    return -SOS_EINVAL;  new_size = SOS_PAGE_ALIGN_SUP(new_size);    /* Lookup a VR overlapping the address range */  vr = find_first_intersecting_vr(as, old_uaddr, old_size);  if (! vr)    return -SOS_EINVAL;    /* Make sure there is exactly ONE VR overlapping the area */  if ( (vr->start > old_uaddr)       || (vr->start + vr->size < old_uaddr + old_size) )    return -SOS_EINVAL;  /* Retrieve the prev/next VR if they exist (the VR are on circular     list) */  prev_vr = vr->prev_in_as;  if (prev_vr->start >= vr->start)    prev_vr = NULL;

⌨️ 快捷键说明

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