1860001 #include <kernel/proc.h>
1860002 #include <errno.h>
1860003 #include <fcntl.h>
1860004 //----------------------------------------------------------------------
1860005 int
1860006 proc_sys_exec (uint16_t *sp, segment_t *segment_d, pid_t pid,
1860007 const char *path,
1860008 unsigned int argc, char *arg_data,
1860009 unsigned int envc, char *env_data)
1860010 {
1860011 unsigned int i;
1860012 unsigned int j;
1860013 char *arg;
1860014 char *env;
1860015 char *envp[ARG_MAX/16];
1860016 char *argv[ARG_MAX/16];
1860017 size_t size;
1860018 size_t arg_data_size;
1860019 size_t env_data_size;
1860020 unsigned int p_off;
1860021 inode_t *inode;
1860022 ssize_t size_read;
1860023 header_t header;
1860024 unsigned long int s; // Help calculating process sizes.
1860025 uint16_t new_sp;
1860026 uint16_t envp_address;
1860027 uint16_t argv_address;
1860028 size_t process_size_i;
1860029 size_t process_size_d;
1860030 char buffer[MEM_BLOCK_SIZE];
1860031 uint16_t stack_element;
1860032 off_t inode_start;
1860033 addr_t memory_start;
1860034 addr_t previous_address_i;
1860035 segment_t previous_segment_i;
1860036 size_t previous_size_i;
1860037 addr_t previous_address_d;
1860038 segment_t previous_segment_d;
1860039 size_t previous_size_d;
1860040 int status;
1860041 memory_t allocated_i;
1860042 memory_t allocated_d;
1860043 pid_t extra;
1860044 int proc_count;
1860045 file_t *file;
1860046 int fdn;
1860047 dev_t device;
1860048 int eof;
1860049 //
1860050 // Check for limits.
1860051 //
1860052 if (argc > (ARG_MAX/16) || envc > (ARG_MAX/16))
1860053 {
1860054 errset (ENOMEM);
1860055 return (-1);
1860056 }
1860057 //
1860058 // Scan arguments to calculate the full size and the relative
1860059 // pointers. The final size is rounded to 2, for the stack.
1860060 //
1860061 arg = arg_data;
1860062 for (i = 0, j = 0; i < argc; i++)
1860063 {
1860064 argv[i] = (char *) j; // Relative pointer inside
1860065 // the `arg_data'.
1860066 size = strlen (arg);
1860067 arg += size + 1;
1860068 j += size + 1;
1860069 }
1860070 arg_data_size = j;
1860071 if (arg_data_size % 2)
1860072 {
1860073 arg_data_size++;
1860074 }
1860075 //
1860076 // Scan environment variables to calculate the full size and the
1860077 // relative pointers. The final size is rounded to 2, for the stack.
1860078 //
1860079 env = env_data;
1860080 for (i = 0, j = 0; i < envc; i++)
1860081 {
1860082 envp[i] = (char *) j; // Relative pointer inside
1860083 // the `env_data'.
1860084 size = strlen (env);
1860085 env += size + 1;
1860086 j += size + 1;
1860087 }
1860088 env_data_size = j;
1860089 if (env_data_size % 2)
1860090 {
1860091 env_data_size++;
1860092 }
1860093 //
1860094 // Read the inode related to the executable file name.
1860095 // Function path_inode() includes the inode get procedure.
1860096 //
1860097 inode = path_inode (pid, path);
1860098 if (inode == NULL)
1860099 {
1860100 errset (ENOENT); // No such file or directory.
1860101 return (-1);
1860102 }
1860103 //
1860104 // Check for permissions.
1860105 //
1860106 status = inode_check (inode, S_IFREG, 5, proc_table[pid].euid);
1860107 if (status != 0)
1860108 {
1860109 //
1860110 // File is not of a valid type or permission are not
1860111 // sufficient: release the executable file inode
1860112 // and return with an error.
1860113 //
1860114 inode_put (inode);
1860115 errset (EACCES); // Permission denied.
1860116 return (-1);
1860117 }
1860118 //
1860119 // Read the header from the executable file.
1860120 //
1860121 size_read = inode_file_read (inode, (off_t) 0, &header,
1860122 (sizeof header), &eof);
1860123 if (size_read != (sizeof header))
1860124 {
1860125 //
1860126 // The file is shorter than the executable header, so, it isn't
1860127 // an executable: release the file inode and return with an
1860128 // error.
1860129 //
1860130 inode_put (inode);
1860131 errset (ENOEXEC);
1860132 return (-1);
1860133 }
1860134 if (header.magic0 != MAGIC_OS16 || header.magic1 != MAGIC_OS16_APPL)
1860135 {
1860136 //
1860137 // The header does not have the expected magic numbers, so,
1860138 // it isn't a valid executable: release the file inode and
1860139 // return with an error.
1860140 //
1860141 inode_put (inode);
1860142 errset (ENOEXEC);
1860143 return (-1); // This is not a valid executable!
1860144 }
1860145 //
1860146 // Calculate data size.
1860147 //
1860148 s = header.ebss;
1860149 if (header.ssize == 0)
1860150 {
1860151 s += 0x10000L; // Zero means max size.
1860152 }
1860153 else
1860154 {
1860155 s += header.ssize;
1860156 }
1860157 if (s > 0xFFFF)
1860158 {
1860159 process_size_d = 0x0000; // 0x0000 means the maximum size:
1860160 // 0x10000.
1860161 new_sp = 0x0000; // 0x0000 is like 0x10000 and the first
1860162 // push moves SP to 0xFFFE.
1860163 }
1860164 else
1860165 {
1860166 process_size_d = s;
1860167 new_sp = process_size_d;
1860168 if (new_sp % 2)
1860169 {
1860170 new_sp--; // The stack pointer should be even.
1860171 }
1860172 }
1860173 //
1860174 // Calculate code size.
1860175 //
1860176 if (header.segoff == 0)
1860177 {
1860178 process_size_i = process_size_d;
1860179 }
1860180 else
1860181 {
1860182 process_size_i = header.segoff * 16;
1860183 }
1860184 //
1860185 // Allocate memory: code and data segments.
1860186 //
1860187 status = mb_alloc_size (process_size_i, &allocated_i);
1860188 if (status < 0)
1860189 {
1860190 //
1860191 // The program instructions (code segment) cannot be loaded
1860192 // into memory: release the executable file inode and return
1860193 // with an error.
1860194 //
1860195 inode_put (inode);
1860196 errset (ENOMEM); // Not enough space.
1860197 return ((pid_t) -1);
1860198 }
1860199 if (header.segoff == 0)
1860200 {
1860201 //
1860202 // Code and data segments are the same: no need
1860203 // to allocate more memory for the data segment.
1860204 //
1860205 allocated_d.address = allocated_i.address;
1860206 allocated_d.segment = allocated_i.segment;
1860207 allocated_d.size = allocated_i.size;
1860208 }
1860209 else
1860210 {
1860211 //
1860212 // Code and data segments are different: the data
1860213 // segment memory is allocated.
1860214 //
1860215 status = mb_alloc_size (process_size_d, &allocated_d);
1860216 if (status < 0)
1860217 {
1860218 //
1860219 // The separated program data (data segment) cannot be loaded
1860220 // into memory: free the already allocated memory for the
1860221 // program instructions, release the executable file inode
1860222 // and return with an error.
1860223 //
1860224 mb_free (allocated_i.address, allocated_i.size);
1860225 inode_put (inode);
1860226 errset (ENOMEM); // Not enough space.
1860227 return ((pid_t) -1);
1860228 }
1860229 }
1860230 //
1860231 // Load executable in memory.
1860232 //
1860233 if (header.segoff == 0)
1860234 {
1860235 //
1860236 // Code and data share the same segment.
1860237 //
1860238 for (eof = 0, memory_start = allocated_i.address,
1860239 inode_start = 0, size_read = 0;
1860240 inode_start < inode->size && !eof;
1860241 inode_start += size_read)
1860242 {
1860243 memory_start += size_read;
1860244 //
1860245 // Read a block of memory.
1860246 //
1860247 size_read = inode_file_read (inode, inode_start,
1860248 buffer, MEM_BLOCK_SIZE, &eof);
1860249 if (size_read < 0)
1860250 {
1860251 //
1860252 // Free memory and inode.
1860253 //
1860254 mb_free (allocated_i.address, allocated_i.size);
1860255 inode_put (inode);
1860256 errset (EIO);
1860257 return (-1);
1860258 }
1860259 //
1860260 // Copy inside the right position to be executed.
1860261 //
1860262 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE, memory_start, buffer,
1860263 (size_t) size_read, NULL);
1860264 }
1860265 }
1860266 else
1860267 {
1860268 //
1860269 // Code and data with different segments.
1860270 //
1860271 for (eof = 0, memory_start = allocated_i.address,
1860272 inode_start = 0, size_read = 0;
1860273 inode_start < process_size_i && !eof;
1860274 inode_start += size_read)
1860275 {
1860276 memory_start += size_read;
1860277 //
1860278 // Read a block of memory
1860279 //
1860280 size_read = inode_file_read (inode, inode_start,
1860281 buffer, MEM_BLOCK_SIZE, &eof);
1860282 if (size_read < 0)
1860283 {
1860284 //
1860285 // Free memory and inode.
1860286 //
1860287 mb_free (allocated_i.address, allocated_i.size);
1860288 mb_free (allocated_d.address, allocated_d.size);
1860289 inode_put (inode);
1860290 errset (EIO);
1860291 return (-1);
1860292 }
1860293 //
1860294 // Copy inside the right position to be executed.
1860295 //
1860296 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE, memory_start, buffer,
1860297 (size_t) size_read, NULL);
1860298 }
1860299 for (eof = 0, memory_start = allocated_d.address,
1860300 inode_start = (header.segoff * 16), size_read = 0;
1860301 inode_start < inode->size && !eof;
1860302 inode_start += size_read)
1860303 {
1860304 memory_start += size_read;
1860305 //
1860306 // Read a block of memory
1860307 //
1860308 size_read = inode_file_read (inode, inode_start,
1860309 buffer, MEM_BLOCK_SIZE, &eof);
1860310 if (size_read < 0)
1860311 {
1860312 //
1860313 // Free memory and inode.
1860314 //
1860315 mb_free (allocated_i.address, allocated_i.size);
1860316 mb_free (allocated_d.address, allocated_d.size);
1860317 inode_put (inode);
1860318 errset (EIO);
1860319 return (-1);
1860320 }
1860321 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE, memory_start, buffer,
1860322 (size_t) size_read, NULL);
1860323 }
1860324 }
1860325 //
1860326 // The executable file was successfully loaded in memory:
1860327 // release the executable file inode.
1860328 //
1860329 inode_put (inode);
1860330 //
1860331 // Put environment data inside the stack.
1860332 //
1860333 new_sp -= env_data_size; //------------------------------- environment
1860334 mem_copy (address (seg_d (), (unsigned int) env_data),
1860335 (allocated_d.address + new_sp), env_data_size);
1860336 //
1860337 // Put arguments data inside the stack.
1860338 //
1860339 new_sp -= arg_data_size; //--------------------------------- arguments
1860340 mem_copy (address (seg_d (), (unsigned int) arg_data),
1860341 (allocated_d.address + new_sp), arg_data_size);
1860342 //
1860343 // Put envp[] inside the stack, updating all the pointers.
1860344 //
1860345 new_sp -= 2; //-------------------------------------------------- NULL
1860346 stack_element = NULL;
1860347 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860348 (allocated_d.address + new_sp),
1860349 &stack_element, (sizeof stack_element), NULL);
1860350 //
1860351 p_off = new_sp; //
1860352 p_off += 2; // Calculate memory pointers from
1860353 p_off += arg_data_size; // original relative pointers,
1860354 for (i = 0; i < envc; i++) // inside the environment array
1860355 { // of pointers.
1860356 envp[i] += p_off; //
1860357 } //
1860358 //
1860359 new_sp -= (envc * (sizeof (char *))); //---------------------- *envp[]
1860360 mem_copy (address (seg_d (), (unsigned int) envp),
1860361 (allocated_d.address + new_sp),
1860362 (envc * (sizeof (char *))));
1860363 //
1860364 // Save the envp[] location, needed in the following.
1860365 //
1860366 envp_address = new_sp;
1860367 //
1860368 // Put argv[] inside the stack, updating all the pointers.
1860369 //
1860370 new_sp -= 2; //-------------------------------------------------- NULL
1860371 stack_element = NULL;
1860372 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860373 (allocated_d.address + new_sp),
1860374 &stack_element, (sizeof stack_element), NULL);
1860375 //
1860376 p_off = new_sp; //
1860377 p_off += 2 ; // Calculate memory pointers
1860378 p_off += (envc * (sizeof (char *))); // from original relative
1860379 p_off += 2; // pointers, inside the
1860380 for (i = 0; i < argc; i++) // arguments array of
1860381 { // pointers.
1860382 argv[i] += p_off; //
1860383 } //
1860384 //
1860385 new_sp -= (argc * (sizeof (char *))); //---------------------- *argv[]
1860386 mem_copy (address (seg_d (), (unsigned int) argv),
1860387 (allocated_d.address + new_sp),
1860388 (argc * (sizeof (char *))));
1860389 //
1860390 // Save the argv[] location, needed in the following.
1860391 //
1860392 argv_address = new_sp;
1860393 //
1860394 // Put the pointer to the array envp[].
1860395 //
1860396 new_sp -= 2; //-------------------------------------------------- argc
1860397 stack_element = envp_address;
1860398 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860399 (allocated_d.address + new_sp),
1860400 &stack_element, (sizeof stack_element), NULL);
1860401 //
1860402 // Put the pointer to the array argv[].
1860403 //
1860404 new_sp -= 2; //-------------------------------------------------- argc
1860405 stack_element = argv_address;
1860406 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860407 (allocated_d.address + new_sp),
1860408 &stack_element, (sizeof stack_element), NULL);
1860409 //
1860410 // Put argc inside the stack.
1860411 //
1860412 new_sp -= 2; //-------------------------------------------------- argc
1860413 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860414 (allocated_d.address + new_sp),
1860415 &argc, (sizeof argc), NULL);
1860416 //
1860417 // Set the rest of the stack.
1860418 //
1860419 new_sp -= 2; //------------------------------------------------- FLAGS
1860420 stack_element = 0x0200;
1860421 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860422 (allocated_d.address + new_sp),
1860423 &stack_element, (sizeof stack_element), NULL);
1860424 new_sp -= 2; //---------------------------------------------------- CS
1860425 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860426 (allocated_d.address + new_sp),
1860427 &allocated_i.segment, (sizeof allocated_i.segment), NULL);
1860428 new_sp -= 2; //---------------------------------------------------- IP
1860429 stack_element = 0;
1860430 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860431 (allocated_d.address + new_sp),
1860432 &stack_element, (sizeof stack_element), NULL);
1860433 new_sp -= 2; //---------------------------------------------------- ES
1860434 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860435 (allocated_d.address + new_sp),
1860436 &allocated_d.segment, (sizeof allocated_d.segment), NULL);
1860437 new_sp -= 2; //---------------------------------------------------- DS
1860438 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860439 (allocated_d.address + new_sp),
1860440 &allocated_d.segment, (sizeof allocated_d.segment), NULL);
1860441 new_sp -= 2; //---------------------------------------------------- DI
1860442 stack_element = 0;
1860443 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860444 (allocated_d.address + new_sp),
1860445 &stack_element, (sizeof stack_element), NULL);
1860446 new_sp -= 2; //---------------------------------------------------- SI
1860447 stack_element = 0;
1860448 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860449 (allocated_d.address + new_sp),
1860450 &stack_element, (sizeof stack_element), NULL);
1860451 new_sp -= 2; //---------------------------------------------------- BP
1860452 stack_element = 0;
1860453 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860454 (allocated_d.address + new_sp),
1860455 &stack_element, (sizeof stack_element), NULL);
1860456 new_sp -= 2; //---------------------------------------------------- BX
1860457 stack_element = 0;
1860458 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860459 (allocated_d.address + new_sp),
1860460 &stack_element, (sizeof stack_element), NULL);
1860461 new_sp -= 2; //---------------------------------------------------- DX
1860462 stack_element = 0;
1860463 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860464 (allocated_d.address + new_sp),
1860465 &stack_element, (sizeof stack_element), NULL);
1860466 new_sp -= 2; //---------------------------------------------------- CX
1860467 stack_element = 0;
1860468 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860469 (allocated_d.address + new_sp),
1860470 &stack_element, (sizeof stack_element), NULL);
1860471 new_sp -= 2; //---------------------------------------------------- AX
1860472 stack_element = 0;
1860473 dev_io ((pid_t) 0, DEV_MEM, DEV_WRITE,
1860474 (allocated_d.address + new_sp),
1860475 &stack_element, (sizeof stack_element), NULL);
1860476 //
1860477 // Close process file descriptors, if the `FD_CLOEXEC' flag
1860478 // is present.
1860479 //
1860480 for (fdn = 0; fdn < OPEN_MAX; fdn++)
1860481 {
1860482 if (proc_table[pid].fd[0].file != NULL)
1860483 {
1860484 if (proc_table[pid].fd[0].fd_flags & FD_CLOEXEC)
1860485 {
1860486 fd_close (pid, fdn);
1860487 }
1860488 }
1860489 }
1860490 //
1860491 // Select device for standard I/O, if a standard I/O stream must be
1860492 // opened.
1860493 //
1860494 if (proc_table[pid].device_tty != 0)
1860495 {
1860496 device = proc_table[pid].device_tty;
1860497 }
1860498 else
1860499 {
1860500 device = DEV_TTY;
1860501 }
1860502 //
1860503 // Prepare missing standard file descriptors. The function
1860504 // `file_stdio_dev_make()' arranges the value for `errno' if
1860505 // necessary. If a standard file descriptor cannot be allocated,
1860506 // the program is left without it.
1860507 //
1860508 if (proc_table[pid].fd[0].file == NULL)
1860509 {
1860510 file = file_stdio_dev_make (device, S_IFCHR, O_RDONLY);
1860511 if (file != NULL) // stdin
1860512 {
1860513 proc_table[pid].fd[0].fl_flags = O_RDONLY;
1860514 proc_table[pid].fd[0].fd_flags = 0;
1860515 proc_table[pid].fd[0].file = file;
1860516 proc_table[pid].fd[0].file->offset = 0;
1860517 }
1860518 }
1860519 if (proc_table[pid].fd[1].file == NULL)
1860520 {
1860521 file = file_stdio_dev_make (device, S_IFCHR, O_WRONLY);
1860522 if (file != NULL) // stdout
1860523 {
1860524 proc_table[pid].fd[1].fl_flags = O_WRONLY;
1860525 proc_table[pid].fd[1].fd_flags = 0;
1860526 proc_table[pid].fd[1].file = file;
1860527 proc_table[pid].fd[1].file->offset = 0;
1860528 }
1860529 }
1860530 if (proc_table[pid].fd[2].file == NULL)
1860531 {
1860532 file = file_stdio_dev_make (device, S_IFCHR, O_WRONLY);
1860533 if (file != NULL) // stderr
1860534 {
1860535 proc_table[pid].fd[2].fl_flags = O_WRONLY;
1860536 proc_table[pid].fd[2].fd_flags = 0;
1860537 proc_table[pid].fd[2].file = file;
1860538 proc_table[pid].fd[2].file->offset = 0;
1860539 }
1860540 }
1860541 //
1860542 // Prepare to switch
1860543 //
1860544 previous_address_i = proc_table[pid].address_i;
1860545 previous_segment_i = proc_table[pid].segment_i;
1860546 previous_size_i = proc_table[pid].size_i;
1860547 previous_address_d = proc_table[pid].address_d;
1860548 previous_segment_d = proc_table[pid].segment_d;
1860549 previous_size_d = proc_table[pid].size_d;
1860550 //
1860551 proc_table[pid].address_i = allocated_i.address;
1860552 proc_table[pid].segment_i = allocated_i.segment;
1860553 proc_table[pid].size_i = allocated_i.size;
1860554 proc_table[pid].address_d = allocated_d.address;
1860555 proc_table[pid].segment_d = allocated_d.segment;
1860556 proc_table[pid].size_d = allocated_d.size;
1860557 proc_table[pid].sp = new_sp;
1860558 strncpy (proc_table[pid].name, path, PATH_MAX);
1860559 //
1860560 // Ensure to have a terminated string.
1860561 //
1860562 proc_table[pid].name[PATH_MAX-1] = 0;
1860563 //
1860564 // Free data segment memory.
1860565 //
1860566 mb_free (previous_address_d, previous_size_d);
1860567 //
1860568 // Free code segment memory if it is
1860569 // different from the data segment.
1860570 //
1860571 if (previous_segment_i != previous_segment_d)
1860572 {
1860573 //
1860574 // Must verify if no other process is
1860575 // using the same memory.
1860576 //
1860577 for (proc_count = 0, extra = 0; extra < PROCESS_MAX; extra++)
1860578 {
1860579 if (proc_table[extra].status == PROC_EMPTY ||
1860580 proc_table[extra].status == PROC_ZOMBIE)
1860581 {
1860582 continue;
1860583 }
1860584 if (previous_segment_i == proc_table[extra].segment_i)
1860585 {
1860586 proc_count++;
1860587 }
1860588 }
1860589 if (proc_count == 0)
1860590 {
1860591 //
1860592 // The code segment can be released, because no other
1860593 // process is using it.
1860594 //
1860595 mb_free (previous_address_i, previous_size_i);
1860596 }
1860597 }
1860598 //
1860599 // Change the segment and the stack pointer, from the interrupt.
1860600 //
1860601 *segment_d = proc_table[pid].segment_d;
1860602 *sp = proc_table[pid].sp;
1860603 //
1860604 return (0);
1860605 }
|