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

Last change on this file since 633 was 625, checked in by alain, 7 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.