Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/syscall/execv.c
2093 views
1
#include <types.h>
2
#include <lib.h>
3
#include <copyinout.h>
4
#include <proc.h>
5
#include <thread.h>
6
#include <current.h>
7
#include <filedesc.h>
8
#include <addrspace.h>
9
#include <kern/fcntl.h>
10
#include <limits.h>
11
#include <kern/errno.h>
12
#include <machine/trapframe.h>
13
#include <synch.h>
14
#include <vfs.h>
15
#include <syscall.h>
16
17
static char karg[ARG_MAX];
18
static unsigned char kargbuf[ARG_MAX];
19
20
#define MAX_PROG_NAME 32
21
22
/**
23
* given a string, and an align parameter
24
* this function will align its length (by appending zero) to match the required alignment.
25
*/
26
static
27
int
28
align_arg( char arg[ARG_MAX], int align ) {
29
char *p = arg;
30
int len = 0;
31
int diff;
32
33
while( *p++ != '\0' )
34
++len;
35
36
if( ++len % align == 0 )
37
return len;
38
39
diff = align - ( len % align );
40
while( diff-- ) {
41
*(++p) = '\0';
42
++len;
43
}
44
45
return len;
46
}
47
48
/**
49
* return the nearest length aligned to alignment.
50
*/
51
static
52
int
53
get_aligned_length( char arg[ARG_MAX], int alignment ) {
54
char *p = arg;
55
int len = 0;
56
57
while( *p++ != '\0' )
58
++len;
59
60
if( ++len % 4 == 0 )
61
return len;
62
63
return len + (alignment - ( len % alignment ) );
64
}
65
66
static
67
int
68
copy_args( userptr_t uargs, int *nargs, int *buflen ) {
69
int i = 0;
70
int err;
71
int nlast = 0;
72
char *ptr;
73
unsigned char *p_begin = NULL;
74
unsigned char *p_end = NULL;
75
uint32_t offset;
76
uint32_t last_offset;
77
78
//check whether we got a valid pointer.
79
if( uargs == NULL )
80
return EFAULT;
81
82
//initialize the numbe of arguments and the buffer size
83
*nargs = 0;
84
*buflen = 0;
85
86
//copy-in kargs.
87
i = 0;
88
while( ( err = copyin( (userptr_t)uargs + i * 4, &ptr, sizeof( ptr ) ) ) == 0 ) {
89
if( ptr == NULL )
90
break;
91
err = copyinstr( (userptr_t)ptr, karg, sizeof( karg ), NULL );
92
if( err )
93
return err;
94
95
++i;
96
*nargs += 1;
97
*buflen += get_aligned_length( karg, 4 ) + sizeof( char * );
98
}
99
100
//if there is a problem, and we haven't read a single argument
101
//that means the given user argument pointer is invalid.
102
if( i == 0 && err )
103
return err;
104
105
//account for NULL also.
106
*nargs += 1;
107
*buflen += sizeof( char * );
108
109
110
//loop over the arguments again, building karbuf.
111
i = 0;
112
p_begin = kargbuf;
113
p_end = kargbuf + (*nargs * sizeof( char * ));
114
nlast = 0;
115
last_offset = *nargs * sizeof( char * );
116
while( ( err = copyin( (userptr_t)uargs + i * 4, &ptr, sizeof( ptr ) ) ) == 0 ) {
117
if( ptr == NULL )
118
break;
119
err = copyinstr( (userptr_t)ptr, karg, sizeof( karg ), NULL );
120
if( err )
121
return err;
122
123
offset = last_offset + nlast;
124
nlast = align_arg( karg, 4 );
125
126
//copy the integer into 4 bytes.
127
*p_begin = offset & 0xff;
128
*(p_begin + 1) = (offset >> 8) & 0xff;
129
*(p_begin + 2) = (offset >> 16) & 0xff;
130
*(p_begin + 3) = (offset >> 24) & 0xff;
131
132
//copy the string the buffer.
133
memcpy( p_end, karg, nlast );
134
p_end += nlast;
135
136
//advance p_begin by 4 bytes.
137
p_begin += 4;
138
139
//adjust last offset
140
last_offset = offset;
141
++i;
142
}
143
144
//set the NULL pointer (i.e., it takes 4 zero bytes.)
145
*p_begin = 0;
146
*(p_begin+1) = 0;
147
*(p_begin+2) = 0;
148
*(p_begin+3) = 0;
149
150
return 0;
151
}
152
153
static
154
int
155
adjust_kargbuf( int nparams, vaddr_t stack_ptr ) {
156
int i;
157
uint32_t new_offset = 0;
158
uint32_t old_offset = 0;
159
int index;
160
161
for( i = 0; i < nparams-1; ++i ) {
162
index = i * sizeof( char * );
163
//read the old offset.
164
old_offset = (( 0xFF & kargbuf[index+3] ) << 24) | (( 0xFF & kargbuf[index+2]) << 16) |
165
(( 0xFF & kargbuf[index+1]) << 8) | (0xFF & kargbuf[index]);
166
167
//calculate the new offset
168
new_offset = stack_ptr + old_offset;
169
170
//store it instead of the old one.
171
memcpy( kargbuf + index, &new_offset, sizeof( int ) );
172
}
173
174
return 0;
175
}
176
177
int
178
sys_execv( userptr_t upname, userptr_t uargs ) {
179
struct addrspace *as_new = NULL;
180
struct addrspace *as_old = NULL;
181
struct vnode *vn = NULL;
182
vaddr_t entry_ptr;
183
vaddr_t stack_ptr;
184
int err;
185
char kpname[MAX_PROG_NAME];
186
int nargs;
187
int buflen;
188
189
KASSERT( curthread != NULL );
190
KASSERT( curthread->td_proc != NULL );
191
192
(void)uargs;
193
194
//lock the execv args
195
lock_acquire( lk_exec );
196
197
//copy the old addrspace just in case.
198
as_old = curthread->t_addrspace;
199
200
//copyin the program name.
201
err = copyinstr( upname, kpname, sizeof( kpname ), NULL );
202
if( err ) {
203
lock_release( lk_exec );
204
return err;
205
}
206
207
//try to open the given executable.
208
err = vfs_open( kpname, O_RDONLY, 0, &vn );
209
if( err ) {
210
lock_release( lk_exec );
211
return err;
212
}
213
214
//copy the arguments into the kernel buffer.
215
err = copy_args( uargs, &nargs, &buflen );
216
if( err ) {
217
lock_release( lk_exec );
218
vfs_close( vn );
219
return err;
220
}
221
222
//create the new addrspace.
223
as_new = as_create();
224
if( as_new == NULL ) {
225
lock_release( lk_exec );
226
vfs_close( vn );
227
return ENOMEM;
228
}
229
230
//activate the new addrspace.
231
as_activate( as_new );
232
233
//temporarily switch the addrspaces.
234
curthread->t_addrspace = as_new;
235
236
//load the elf executable.
237
err = load_elf( vn, &entry_ptr );
238
if( err ) {
239
curthread->t_addrspace = as_old;
240
as_activate( as_old );
241
242
as_destroy( as_new );
243
vfs_close( vn );
244
lock_release( lk_exec );
245
return err;
246
}
247
248
//create a stack for the new addrspace.
249
err = as_define_stack( as_new, &stack_ptr );
250
if( err ) {
251
curthread->t_addrspace = as_old;
252
as_activate( as_old );
253
254
as_destroy( as_new );
255
vfs_close( vn );
256
lock_release( lk_exec );
257
return err;
258
}
259
260
//adjust the stackptr to reflect the change
261
stack_ptr -= buflen;
262
err = adjust_kargbuf( nargs, stack_ptr );
263
if( err ) {
264
curthread->t_addrspace = as_old;
265
as_activate( as_old );
266
267
as_destroy( as_new );
268
vfs_close( vn );
269
lock_release( lk_exec );
270
return err;
271
}
272
273
//copy the arguments into the new user stack.
274
err = copyout( kargbuf, (userptr_t)stack_ptr, buflen );
275
if( err ) {
276
curthread->t_addrspace = as_old;
277
as_activate( as_old );
278
as_destroy( as_new );
279
vfs_close( vn );
280
lock_release( lk_exec );
281
return err;
282
}
283
284
//reelase lk_exec
285
lock_release( lk_exec );
286
287
//no need for it anymore.
288
vfs_close( vn );
289
290
//we are good to go.
291
as_destroy( as_old );
292
293
//off we go to userland.
294
enter_new_process( nargs-1, (userptr_t)stack_ptr, stack_ptr, entry_ptr );
295
296
panic( "execv: we should not be here." );
297
return EINVAL;
298
}
299
300