source: trunk/kernel/syscalls/sys_write.c @ 634

Last change on this file since 634 was 625, checked in by alain, 6 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

File size: 8.9 KB
Line 
1/*
2 * sys_write.c - Kernel function implementing the "write" system call.
3 *
4 * Author        Alain Greiner (2016,2017,2018,2019)
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_vmm.h>
27#include <hal_uspace.h>
28#include <hal_irqmask.h>
29#include <hal_special.h>
30#include <errno.h>
31#include <vfs.h>
32#include <vmm.h>
33#include <thread.h>
34#include <printk.h>
35#include <process.h>
36
37
38extern uint32_t enter_sys_write;
39extern uint32_t enter_devfs_write;
40extern uint32_t enter_txt_write;
41extern uint32_t enter_chdev_cmd_write;
42extern uint32_t enter_chdev_server_write;
43extern uint32_t enter_tty_cmd_write;
44extern uint32_t enter_tty_isr_write;
45extern uint32_t exit_tty_isr_write;
46extern uint32_t exit_tty_cmd_write;
47extern uint32_t exit_chdev_server_write;
48extern uint32_t exit_chdev_cmd_write;
49extern uint32_t exit_txt_write;
50extern uint32_t exit_devfs_write;
51extern uint32_t exit_sys_write;
52
53//////////////////////////////////
54int sys_write( uint32_t   file_id,
55               void     * vaddr,
56               uint32_t   count )
57{
58    error_t       error;
59    vseg_t      * vseg;            // required for user space checking
60        xptr_t        file_xp;         // remote file extended pointer
61    vfs_file_t  * file_ptr;        // remote file local pointer
62    cxy_t         file_cxy;        // remote file cluster identifier
63    uint32_t      file_type;       // file type
64    uint32_t      file_offset;     // current file offset
65    uint32_t      file_attr;       // file_attribute
66    vfs_inode_t * inode_ptr;       // local pointer on associated inode
67    uint32_t      nbytes;          // number of bytes actually written
68    reg_t         save_sr;         // required to enable IRQs during syscall
69
70        thread_t    * this = CURRENT_THREAD;
71        process_t   * process = this->process;
72
73#if (DEBUG_SYS_WRITE || CONFIG_INSTRUMENTATION_SYSCALLS)
74uint64_t     tm_start = hal_get_cycles();
75#endif
76
77#if DEBUG_SYS_WRITE
78if( DEBUG_SYS_WRITE < tm_start )
79printk("\n[%s] thread[%x,%x] enter / vaddr %x / %d bytes / cycle %d\n",
80__FUNCTION__, process->pid, this->trdid, vaddr, count, (uint32_t)tm_start );
81#endif
82 
83#if (DEBUG_SYS_WRITE & 1)
84enter_sys_write = (uint32_t)tm_start;
85#endif
86
87    // check file_id argument
88        if( file_id >= CONFIG_PROCESS_FILE_MAX_NR )
89        {
90
91#if DEBUG_SYSCALLS_ERROR
92printk("\n[ERROR] in %s : thread[%x,%x] illegal file descriptor index %d\n",
93__FUNCTION__, process->pid, this->trdid, file_id );
94#endif
95        this->errno = EBADFD;
96                return -1;
97        }
98
99    // check user buffer in user space
100    error = vmm_get_vseg( process , (intptr_t)vaddr , &vseg );
101
102    if ( error )
103    {
104
105#if DEBUG_SYSCALLS_ERROR
106printk("\n[ERROR] in %s : thread[%x,%x] user buffer unmapped %x\n",
107__FUNCTION__ , process->pid, this->trdid, (intptr_t)vaddr );
108hal_vmm_display( process , false );
109#endif
110                this->errno = EINVAL;
111                return -1;
112    }
113
114    // get extended pointer on remote file descriptor
115    file_xp = process_fd_get_xptr( process , file_id );
116
117    if( file_xp == XPTR_NULL )
118    {
119
120#if DEBUG_SYSCALLS_ERROR
121printk("\n[ERROR] in %s : thread[%x,%x] undefined file descriptor = %d\n",
122__FUNCTION__, process->pid, this->trdid, file_id );
123#endif
124                this->errno = EBADFD;
125                return -1;
126    }
127
128    // get file descriptor cluster and local pointer
129    file_ptr = GET_PTR( file_xp );
130    file_cxy = GET_CXY( file_xp );
131
132    // get file type, offset, aatributes, and associated inode
133    file_type   = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
134    file_offset = hal_remote_l32( XPTR( file_cxy , &file_ptr->offset ) );
135    inode_ptr   = hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
136    file_attr   = hal_remote_l32( XPTR( file_cxy , &file_ptr->attr ) );
137
138    // enable IRQs
139    hal_enable_irq( &save_sr );
140
141    // action depend on file type
142    if( file_type == INODE_TYPE_FILE )  // write to a file mapper
143    {
144        // check file writable
145        if( (file_attr & FD_ATTR_WRITE_ENABLE) == 0 )
146            {
147
148#if DEBUG_SYSCALLS_ERROR
149printk("\n[ERROR] in %s : thread[%x,%x] file %d not writable\n",
150__FUNCTION__ , process->pid, this->trdid, file_id );
151#endif
152            hal_restore_irq( save_sr );
153                    this->errno = EBADFD;
154                    return -1;
155            }
156
157        // move count bytes to mapper
158        nbytes = vfs_user_move( false,               // from buffer to mapper
159                                file_xp,
160                                vaddr, 
161                                count );
162        if ( nbytes != count )
163        {
164
165#if DEBUG_SYSCALLS_ERROR
166printk("\n[ERROR] in %s : thread[%x,%x] cannot write %d bytes into file %d\n",
167__FUNCTION__ , process->pid, this->trdid, count, file_id );
168#endif
169            hal_restore_irq( save_sr );
170            this->errno = EIO;
171            return -1;
172
173        }
174
175        // update file size in inode descriptor
176        // only if (file_offset + count) > current_size
177        // note: the parent directory entry in mapper will
178        // be updated by the close syscall     
179        xptr_t inode_xp = XPTR( file_cxy , inode_ptr );
180        vfs_inode_update_size( inode_xp , file_offset + count );
181    }
182    else if( file_type == INODE_TYPE_DEV )  // write to TXT device
183    {
184        // move count bytes to device
185        nbytes = devfs_user_move( false,             // from buffer to device
186                                  file_xp,
187                                  vaddr,
188                                  count );
189        if( nbytes != count )
190        {
191
192#if DEBUG_SYSCALLS_ERROR
193printk("\n[ERROR] in %s : thread[%x,‰x] cannot write data to file %d\n",
194__FUNCTION__ , process->pid, this->trdid, file_id );
195#endif
196            hal_restore_irq( save_sr );
197            this->errno = EIO;
198            return -1;
199        }
200    }
201    else  // not FILE and not DEV
202    {
203
204#if DEBUG_SYSCALLS_ERROR
205printk("\n[ERROR] in %s : thread[%x,%x] / illegal inode type %\n",
206__FUNCTION__, vfs_inode_type_str( file_type ) );
207#endif
208        hal_restore_irq( save_sr );
209                this->errno = EBADFD;
210                return -1;
211    }
212
213    // restore IRQs
214    hal_restore_irq( save_sr );
215
216    hal_fence();
217
218#if (DEBUG_SYS_WRITE || CONFIG_INSTRUMENTATION_SYSCALLS)
219uint64_t     tm_end = hal_get_cycles();
220#endif
221
222#if DEBUG_SYS_WRITE
223if( DEBUG_SYS_WRITE < tm_end )
224printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
225__FUNCTION__, process->pid, this->trdid, (uint32_t)tm_end );
226#endif
227 
228#if CONFIG_INSTRUMENTATION_SYSCALLS
229hal_atomic_add( &syscalls_cumul_cost[SYS_WRITE] , tm_end - tm_start );
230hal_atomic_add( &syscalls_occurences[SYS_WRITE] , 1 );
231#endif
232
233#if (DEBUG_SYS_WRITE & 1)
234exit_sys_write = (uint32_t)tm_end;
235
236printk("\n***** timing to write a string *****\n"
237" - enter_sys_write          = %d / delta %d\n"
238" - enter_devfs_write        = %d / delta %d\n"
239" - enter_txt_write          = %d / delta %d\n"
240" - enter_chdev_cmd_write    = %d / delta %d\n"
241" - enter_chdev_server_write = %d / delta %d\n"
242" - enter_tty_cmd_write      = %d / delta %d\n"
243" - enter_tty_isr_write      = %d / delta %d\n"
244" - exit_tty_isr_write       = %d / delta %d\n"
245" - exit_tty_cmd_write       = %d / delta %d\n"
246" - exit_chdev_server_write  = %d / delta %d\n"
247" - exit_chdev_cmd_write     = %d / delta %d\n"
248" - exit_txt_write           = %d / delta %d\n"
249" - exit_devfs_write         = %d / delta %d\n"
250" - exit_sys_write           = %d / delta %d\n",
251enter_sys_write          , 0 ,
252enter_devfs_write        , enter_devfs_write        - enter_sys_write          ,
253enter_txt_write          , enter_txt_write          - enter_devfs_write        ,
254enter_chdev_cmd_write    , enter_chdev_cmd_write    - enter_txt_write          ,
255enter_chdev_server_write , enter_chdev_server_write - enter_chdev_cmd_write    ,
256enter_tty_cmd_write      , enter_tty_cmd_write      - enter_chdev_server_write ,
257enter_tty_isr_write      , enter_tty_isr_write      - enter_tty_cmd_write      ,
258exit_tty_isr_write       , exit_tty_isr_write       - enter_tty_isr_write      ,
259exit_tty_cmd_write       , exit_tty_cmd_write       - exit_tty_isr_write       ,
260exit_chdev_server_write  , exit_chdev_server_write  - exit_tty_cmd_write       ,
261exit_chdev_cmd_write     , exit_chdev_cmd_write     - exit_chdev_server_write  ,
262exit_txt_write           , exit_txt_write           - exit_chdev_cmd_write     ,
263exit_devfs_write         , exit_devfs_write         - exit_txt_write           ,
264exit_sys_write           , exit_sys_write           - exit_devfs_write         );
265#endif
266 
267        return nbytes;
268
269}  // end sys_write()
Note: See TracBrowser for help on using the repository browser.