📄 zero.c
字号:
/* 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/kmalloc.h>#include <sos/physmem.h>#include <hwcore/paging.h>#include <sos/kmem_slab.h>#include <sos/list.h>#include <hwcore/paging.h>#include "zero.h"/** * A mapped page for a shared mapping of /dev/zero */struct zero_mapped_page{ sos_uoffset_t page_id; sos_paddr_t ppage_paddr; struct zero_mapped_page *prev, *next;};/** The Slab cache of shared mapped pages */struct sos_kslab_cache * cache_of_zero_mapped_pages;/** * A mapped /dev/zero resource */struct zero_mapped_resource{ int ref_cnt; /** * For shared mappings: the list of shared pages mapped inside one * or multiple VRs */ struct zero_mapped_page *list_mapped_pages; struct sos_umem_vmm_mapped_resource mr;};/** Helper function to insert the given physical page in the list of physical pages used for shared anonymous mappings */static sos_ret_t insert_anonymous_physpage(struct zero_mapped_resource *mr, sos_paddr_t ppage_paddr, sos_uoffset_t page_id);/** Helper function to insert the given physical page in the list of physical pages used for shared anonymous mappings */static sos_paddr_t lookup_anonymous_physpage(struct zero_mapped_resource *mr, sos_uoffset_t page_id);sos_ret_t sos_dev_zero_subsystem_setup(){ cache_of_zero_mapped_pages = sos_kmem_cache_create("shared anonymous mappings", sizeof(struct zero_mapped_page), 1, 0, SOS_KSLAB_CREATE_MAP | SOS_KSLAB_CREATE_ZERO); if (! cache_of_zero_mapped_pages) return -SOS_ENOMEM; return SOS_OK;}/** Called after the virtual region has been inserted inside its address space */static void zero_ref(struct sos_umem_vmm_vr * vr){ /* Retrieve the 'zero' structure associated with the mapped resource */ struct zero_mapped_resource * zero_resource; zero_resource = (struct zero_mapped_resource*) sos_umem_vmm_get_mapped_resource_of_vr(vr)->custom_data; /* Increment ref counter */ zero_resource->ref_cnt ++;}/** Called when the virtual region is removed from its address space */static void zero_unref(struct sos_umem_vmm_vr * vr){ /* Retrieve the 'zero' structure associated with the mapped resource */ struct zero_mapped_resource * zero_resource; zero_resource = (struct zero_mapped_resource*) sos_umem_vmm_get_mapped_resource_of_vr(vr)->custom_data; /* Decrement ref coutner */ SOS_ASSERT_FATAL(zero_resource->ref_cnt > 0); zero_resource->ref_cnt --; /* Free the resource if it becomes unused */ if (zero_resource->ref_cnt == 0) { /* Delete the list of anonymous shared mappings */ struct zero_mapped_page *zmp; list_collapse(zero_resource->list_mapped_pages, zmp) { /* Unreference the underlying physical page */ sos_physmem_unref_physpage(zmp->ppage_paddr); sos_kfree((sos_vaddr_t)zmp); } sos_kfree((sos_vaddr_t)zero_resource); }}/** MOST IMPORTANT callback ! Called when a thread page faults on the resource's mapping */static sos_ret_t zero_page_in(struct sos_umem_vmm_vr * vr, sos_uaddr_t uaddr, sos_bool_t write_access){ sos_ret_t retval = SOS_OK; sos_paddr_t ppage_paddr; sos_uoffset_t required_page_id; struct zero_mapped_resource * zero_resource; sos_ui32_t vr_prot, vr_flags; /* Retrieve the 'zero' structure associated with the mapped resource */ zero_resource = (struct zero_mapped_resource*) sos_umem_vmm_get_mapped_resource_of_vr(vr)->custom_data; /* Retrieve access rights/flags of the VR */ vr_prot = sos_umem_vmm_get_prot_of_vr(vr); vr_flags = sos_umem_vmm_get_flags_of_vr(vr); /* Identifies the page in the mapping that's being paged-in */ required_page_id = SOS_PAGE_ALIGN_INF(uaddr) - sos_umem_vmm_get_start_of_vr(vr) + sos_umem_vmm_get_offset_in_resource(vr); /* For shared mappings, check if there is a page already mapping the required address */ if (vr_flags & SOS_VR_MAP_SHARED) { ppage_paddr = lookup_anonymous_physpage(zero_resource, required_page_id); if (NULL != (void*)ppage_paddr) { retval = sos_paging_map(ppage_paddr, SOS_PAGE_ALIGN_INF(uaddr), TRUE, vr_prot); return retval; } } /* For write accesses, directly maps a new page. For read accesses, simply map in the zero_page (and wait for COW to handle the next write accesses) */ if (write_access) { /* Allocate a new page for the virtual address */ ppage_paddr = sos_physmem_ref_physpage_new(FALSE); if (! ppage_paddr) return -SOS_ENOMEM; retval = sos_paging_map(ppage_paddr, SOS_PAGE_ALIGN_INF(uaddr), TRUE, vr_prot); if (SOS_OK != retval) { sos_physmem_unref_physpage(ppage_paddr); return retval; } memset((void*)SOS_PAGE_ALIGN_INF(uaddr), 0x0, SOS_PAGE_SIZE); /* For shared mappings, add the page in the list of shared mapped pages */ if (vr_flags & SOS_VR_MAP_SHARED) insert_anonymous_physpage(zero_resource, ppage_paddr, required_page_id); sos_physmem_unref_physpage(ppage_paddr); } else { /* Map-in the zero page in READ ONLY whatever the access_rights or the type (shared/private) of the VR to activate COW */ retval = sos_paging_map(sos_zero_page, SOS_PAGE_ALIGN_INF(uaddr), TRUE, SOS_VM_MAP_PROT_READ); } return retval;}/** The callbacks for a mapped /dev/zero resource */static struct sos_umem_vmm_vr_ops zero_ops = (struct sos_umem_vmm_vr_ops){ .ref = zero_ref, .unref = zero_unref, .page_in = zero_page_in, .unmap = NULL};/** The callback that gets called when the resource gets mapped */static sos_ret_t zero_mmap(struct sos_umem_vmm_vr *vr){ return sos_umem_vmm_set_ops_of_vr(vr, &zero_ops);}/** The function responsible for mapping the /dev/zero resource in user space */sos_ret_t sos_dev_zero_map(struct sos_umem_vmm_as * dest_as, sos_uaddr_t *uaddr, sos_size_t size, sos_ui32_t access_rights, sos_ui32_t flags){ sos_ret_t retval; struct zero_mapped_resource * zero_resource; zero_resource = (struct zero_mapped_resource*) sos_kmalloc(sizeof(*zero_resource), 0); if (! zero_resource) return -SOS_ENOMEM; memset(zero_resource, 0x0, sizeof(*zero_resource)); zero_resource->mr.allowed_access_rights = SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE | SOS_VM_MAP_PROT_EXEC; zero_resource->mr.flags |= SOS_MAPPED_RESOURCE_ANONYMOUS; zero_resource->mr.custom_data = zero_resource; zero_resource->mr.mmap = zero_mmap; retval = sos_umem_vmm_map(dest_as, uaddr, size, access_rights, flags, &zero_resource->mr, 0); if (SOS_OK != retval) { sos_kfree((sos_vaddr_t)zero_resource); return retval; } return SOS_OK;}static sos_ret_t insert_anonymous_physpage(struct zero_mapped_resource *mr, sos_paddr_t ppage_paddr, sos_uoffset_t page_id){ struct zero_mapped_page * zmp = (struct zero_mapped_page*)sos_kmem_cache_alloc(cache_of_zero_mapped_pages, 0); if (! zmp) return -SOS_ENOMEM; zmp->page_id = page_id; zmp->ppage_paddr = ppage_paddr; list_add_head(mr->list_mapped_pages, zmp); sos_physmem_ref_physpage_at(ppage_paddr); return SOS_OK;}static sos_paddr_t lookup_anonymous_physpage(struct zero_mapped_resource *mr, sos_uoffset_t page_id){ struct zero_mapped_page * zmp; int nb_elts; list_foreach_forward(mr->list_mapped_pages, zmp, nb_elts) { if (zmp->page_id == page_id) return zmp->ppage_paddr; } return (sos_paddr_t)NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -