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