source: trunk/kernel/syscalls/sys_readdir.c @ 624

Last change on this file since 624 was 624, checked in by alain, 5 years ago

Fix several bugs to use the instruction MMU in kernel mode
in replacement of the instruction address extension register,
and remove the "kentry" segment.

This version is running on the tsar_generic_iob" platform.

One interesting bug: the cp0_ebase defining the kernel entry point
(for interrupts, exceptions and syscalls) must be initialized
early in kernel_init(), because the VFS initialisation done by
kernel_ini() uses RPCs, and RPCs uses Inter-Processor-Interrup.

File size: 4.2 KB
Line 
1/*
2 * sys_readdir.c - Copy one entry from an open VFS directory to an user buffer.
3 *
4 * Author    Alain Greiner (2016,2017,2018)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <kernel_config.h>
25#include <hal_kernel_types.h>
26#include <hal_uspace.h>
27#include <errno.h>
28#include <thread.h>
29#include <printk.h>
30#include <vfs.h>
31#include <process.h>
32#include <user_dir.h>
33#include <syscalls.h>
34#include <shared_syscalls.h>
35
36///////////////////////////////////////
37int sys_readdir( DIR            * dirp,
38                 struct dirent ** buffer )
39{
40    error_t         error;
41    vseg_t        * vseg;               // for user space checking of buffer
42    xptr_t          dir_xp;             // extended pointer on user_dir structure
43    user_dir_t    * dir_ptr;            // local pointer on user_dir structure
44    cxy_t           dir_cxy;            // user_dir stucture cluster identifier
45    struct dirent * direntp;            // dirent pointer in user space 
46    uint32_t        entries;            // total number of dirent entries
47    uint32_t        current;            // current dirent index
48
49        thread_t  * this    = CURRENT_THREAD;  // client thread
50        process_t * process = this->process;   // client process
51
52#if (DEBUG_SYS_READDIR || CONFIG_INSTRUMENTATION_SYSCALLS)
53uint64_t     tm_start = hal_get_cycles();
54#endif
55
56#if DEBUG_SYS_READDIR
57if( DEBUG_SYS_READDIR < tm_start )
58printk("\n[%s] thread[%x,%x] enter / dirp %x / cycle %d\n",
59__FUNCTION__, process->pid, this->trdid, dirp, (uint32_t)tm_start );
60#endif
61 
62    // check buffer in user space
63    error = vmm_get_vseg( process , (intptr_t)buffer, &vseg );
64
65        if( error )
66        {
67
68#if DEBUG_SYSCALLS_ERROR
69printk("\n[ERROR] in %s / thread[%x,%x] : user buffer %x unmapped\n",
70__FUNCTION__ , process->pid , this->trdid, buffer );
71hal_vmm_display( process , false );
72#endif
73                this->errno = EINVAL;
74                return -1;
75        }       
76
77    // get pointers on user_dir structure from dirp
78    dir_xp  = user_dir_from_ident( (intptr_t)dirp );
79    dir_ptr = GET_PTR( dir_xp );
80    dir_cxy = GET_CXY( dir_xp );
81
82    if( dir_xp == XPTR_NULL )
83        {
84
85#if DEBUG_SYSCALLS_ERROR
86printk("\n[ERROR] in %s / thread[%x,%x] : dirp %x not registered\n",
87__FUNCTION__ , process->pid , this->trdid, dirp );
88#endif
89                this->errno = EBADF;
90                return -1;
91        }       
92
93    // get "current" and "entries_nr" values from user_dir_t structure
94    current = hal_remote_l32( XPTR( dir_cxy , &dir_ptr->current ) );
95    entries = hal_remote_l32( XPTR( dir_cxy , &dir_ptr->entries ) );
96
97    // check "current" index
98    if( current >= entries )
99    {
100        this->errno = 0;
101        return -1;
102    }
103
104    // compute dirent pointer in user space
105    direntp = (struct dirent *)dirp + current;
106
107#if (DEBUG_SYS_READDIR & 1)
108if( DEBUG_SYS_READDIR < tm_start )
109printk("\n[%s] entries = %d / current = %d / direntp = %x\n",
110__FUNCTION__, entries, current, direntp );
111#endif
112
113    // copy dirent pointer to user buffer
114    hal_copy_to_uspace( buffer, &direntp , sizeof(void *) );
115
116    // update current index in user_dir structure
117    hal_remote_atomic_add( XPTR( dir_cxy , &dir_ptr->current ) , 1 );
118
119    hal_fence();
120
121#if (DEBUG_SYS_READDIR || CONFIG_INSTRUMENTATION_SYSCALLS)
122uint64_t     tm_end = hal_get_cycles();
123#endif
124
125#if DEBUG_SYS_READDIR
126if( DEBUG_SYS_READDIR < tm_end )
127printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
128__FUNCTION__, process->pid, this->trdid, (uint32_t)tm_end );
129#endif
130 
131#if CONFIG_INSTRUMENTATION_SYSCALLS
132hal_atomic_add( &syscalls_cumul_cost[SYS_READDIR] , tm_end - tm_start );
133hal_atomic_add( &syscalls_occurences[SYS_READDIR] , 1 );
134#endif
135
136        return 0;
137
138}  // end sys_readdir()
Note: See TracBrowser for help on using the repository browser.