/* * sys_munmap.c - unmap a mapping from process virtual address space * * Authors Alain Greiner (2016,2017,2018,2019) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH 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; version 2.0 of the License. * * ALMOS-MKH 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 ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include //////////////////////////////// int sys_munmap( void * vaddr, uint32_t size ) { error_t error; vseg_t * vseg; reg_t save_sr; // required to enable IRQs thread_t * this = CURRENT_THREAD; process_t * process = this->process; #if (DEBUG_SYS_MUNMAP || CONFIG_INSTRUMENTATION_SYSCALLS) uint64_t tm_start = hal_get_cycles(); #endif #if DEBUG_SYS_MUNMAP if( DEBUG_SYS_MUNMAP < tm_start ) printk("\n[%s] thread[%x,%x] enter / cycle %d\n", __FUNCTION__, process->pid, this->trdid, (uint32_t)tm_start ); #endif // check user buffer is mapped error = vmm_get_vseg( process , (intptr_t)vaddr, &vseg ); if( error ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s : thread[%x,%x] / user buffer unmapped %x\n", __FUNCTION__ , process->pid, this->trdid, (intptr_t)vaddr ); #endif this->errno = EINVAL; return -1; } // compute unmapped region min an max intptr_t addr_min = (intptr_t)vaddr; intptr_t addr_max = addr_min + size; // get vseg min & max addresses intptr_t vseg_min = vseg->min; intptr_t vseg_max = vseg->max; // enable IRQs hal_enable_irq( &save_sr ); // action depend on both vseg and region bases & sizes if( (vseg_min > addr_min) || (vseg_max < addr_max) ) // region not included in vseg { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s : region[%x->%x] / vseg[%x->%x] => non included in vseg\n", __FUNCTION__, process->pid, this->trdid, addr_min, addr_max, vseg_min, vseg_max ); #endif this->errno = EINVAL; return -1; } else if( (vseg_min == addr_min) && (vseg_max == addr_max) ) { #if( DEBUG_SYS_MUNMAP & 1 ) if( DEBUG_SYS_MUNMAP < tm_start ) printk("\n[%s] thread[%x,%x] unmapped region[%x->%x[ / vseg[%x->%x[ => delete vseg\n", __FUNCTION__, process->pid, this->trdid, addr_min, addr_max, vseg_min, vseg_max ); #endif // delete existing vseg vmm_global_delete_vseg( process, vseg_min ); } else if( (vseg_min == addr_min) || (vseg_max == addr_max) ) { #if( DEBUG_SYS_MUNMAP & 1 ) if( DEBUG_SYS_MUNMAP < tm_start ) printk("\n[%s] thread[%x,%x] unmapped region[%x->%x[ / vseg[%x->%x[ => resize vseg\n", __FUNCTION__, process->pid, this->trdid, addr_min, addr_max, vseg_min, vseg_max ); #endif // resize existing vseg vmm_global_resize_vseg( process, vseg_min, addr_min, addr_max - addr_min ); } else // addr_min > vseg_min) && (addr_max < vseg_max) { #if( DEBUG_SYS_MUNMAP & 1 ) if( DEBUG_SYS_MUNMAP < tm_start ) printk("\n[%s] thread[%x,%x] unmapped region[%x->%x[ / vseg[%x->%x[ => create new vseg\n", __FUNCTION__, process->pid, this->trdid, addr_min, addr_max, vseg_min, vseg_max ); #endif // resize existing vseg vmm_global_resize_vseg( process, vseg_min, vseg_min, addr_min - vseg_min ); // create new vseg vmm_create_vseg( process, vseg->type, addr_max, vseg_max - addr_max, vseg->file_offset, vseg->file_size, vseg->mapper_xp, vseg->cxy ); } // restore IRQs hal_restore_irq( save_sr ); #if (DEBUG_SYS_MUNMAP || CONFIG_INSTRUMENTATION_SYSCALLS) uint64_t tm_end = hal_get_cycles(); #endif #if CONFIG_INSTRUMENTATION_SYSCALLS hal_atomic_add( &syscalls_cumul_cost[SYS_MUNMAP] , tm_end - tm_start ); hal_atomic_add( &syscalls_occurences[SYS_MUNMAP] , 1 ); #endif #if DEBUG_SYS_MUNMAP if( DEBUG_SYS_MUNMAP < tm_start ) printk("\n[%s] thread [%x,%x] exit / cycle %d\n", __FUNCTION__ , process->pid, this->trdid, (uint32_t)tm_end ); #endif return 0; } // end sys_munmap()