📄 umem_vmm.c
字号:
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 + -