sys_proc.c

Go to the documentation of this file.
00001 
00007 #include <routix/system.h>
00008 #include <routix/paging.h>
00009 #include <routix/segm.h>
00010 #include <routix/debug.h>
00011 #include <routix/syscalls.h>
00012 #include <sys/syscalls.h>
00013 #include <routix/elf.h>
00014 #include <routix/file.h>
00015 #include <error.h>
00016 #include <routix/timer.h>
00017 #include <routix/kalloc.h>
00018 #include <routix/kstdio.h>
00019 #include <string.h>
00020 #include <routix/task.h>
00021 #include <sys/list.h>
00022 #include <sys/types.h>
00023 #include <routix/signal.h>
00024 
00025 #define RUNSTATS 1
00026 
00028 #define START_PRIORITY 1
00029 
00030 
00032 extern task_struct_t *actual;
00034 extern task_struct_t *init_task;
00035 
00036 int sys_execve (char *nombre, char **arg_p, char **env_p);
00037 inline int count_elements (char **vector);
00038 
00039 // Funciones relacionadas con la llamada "exit"
00040 int sys_exit_mm(void);
00041 int sys_exit_notify(void);
00042 int sys_exit_fs (void);
00043 
00044 
00046 int (*syscall_process[MAX_SYSCALLS]) (void) = {
00047         (int (*) (void)) sys_exec,      
00048         (int (*) (void)) sys_void,      
00049         (int (*) (void)) sys_fork,      
00050         (int (*) (void)) sys_perror,    
00051         (int (*) (void)) sys_renice,    
00052         (int (*) (void)) sys_get_pid,
00053         (int (*) (void)) sys_get_ppid,
00054         (int (*) (void)) sys_exit,
00055         (int (*) (void)) sys_show,
00056         (int (*) (void)) sys_waitpid,
00057         (int (*) (void)) sys_execve
00058 };
00059 
00060    
00062 int sys_void (void)
00063 {
00064     kprintf("\nLlamada a SYS Void\n");
00065         unsigned long *_esp;
00066         __asm__ __volatile__ ("movl %%esp, %0" : "=m" (_esp));
00067         kprintf("VOIDO: valor de ESP: 0x%x\n",   *(_esp));
00068         kprintf("VOIDO: valor de ESP+1: 0x%x\n", *(_esp+1));
00069         kprintf("VOIDO: valor de ESP+2: 0x%x\n", *(_esp+2));
00070         kprintf("VOIDO: valor de ESP+3: 0x%x\n", *(_esp+3));
00071         kprintf("VOIDO: valor de ESP+4: 0x%x\n", *(_esp+4));
00072         kprintf("VOIDO: valor de ESP+5: 0x%x\n", *(_esp+5));
00073         kprintf("VOIDO: valor de ESP+6: 0x%x\n", *(_esp+6));
00074         kprintf("VOIDO: valor de ESP+7: 0x%x\n", *(_esp+7));
00075         kprintf("VOIDO: valor de ESP+8: 0x%x\n", *(_esp+8));
00076         kprintf("VOIDO: valor de ESP+9: 0x%x\n", *(_esp+9));
00077         kprintf("VOIDO: valor de ESP+10: 0x%x\n", *(_esp+10));
00078         kprintf("VOIDO: valor de ESP+11: 0x%x\n", *(_esp+11));
00079         kprintf("VOIDO: valor de ESP+12: 0x%x\n", *(_esp+12));
00080         kprintf("VOIDO: valor de ESP+13: 0x%x\n", *(_esp+13));
00081         kprintf("VOIDO: valor de ESP+14: 0x%x\n", *(_esp+14));
00082         kprintf("VOIDO: valor de ESP+15: 0x%x\n", *(_esp+15));
00083         kprintf("VOIDO: valor de ESP+16: 0x%x\n", *(_esp+16));
00084         kprintf("VOIDO: valor de ESP+17: 0x%x\n", *(_esp+17));
00085 
00086         unsigned long *p = (unsigned long *) *(_esp+9);
00087         p = convertir_direccion (p, actual->cr3_backup);
00088 
00089 
00090         return OK;
00091 }       
00092 
00095 struct int_regs
00096 {
00097     dword ebx;
00098     dword ecx;
00099     dword edx;
00100     dword edi;
00101     dword esi;
00102     dword ebp;
00103     dword eip;
00104     dword cs;
00105     dword eflags;
00106     dword esp;
00107     dword ss;
00108 };
00109 
00110 
00112 int sys_fork (void)
00113 {
00114         cli();
00115 
00116     struct task_struct_t *new_task;
00117     // Punteros al contexto de la tarea (en el stack de modo kernel)
00118     struct int_regs *new, *current;
00119     struct int_regs_ext *new_ext;
00120     word i;
00121 
00122     // init_new_task devuelve la tarea creada como TASK_STOPPED, la mantendremos así hasta el final    
00123     new_task = init_new_task (0,0,0,0,0, actual->descripcion, actual->prioridad);
00124     
00125     current = (struct int_regs *) ((actual->esp0 & 0xfffff000) + PAGINA_SIZE - sizeof(struct int_regs));
00126     new = (struct int_regs *) ((new_task->esp0 & 0xfffff000) + PAGINA_SIZE - sizeof(struct int_regs));
00127 
00128     new_ext = (struct int_regs_ext *) ((new_task->esp0 & 0xfffff000) + PAGINA_SIZE - sizeof(struct int_regs_ext));
00129     new_ext = GET_CONTEXT(new_task);
00130     
00131     new_ext->ds = DESC_DATA_USUARIO;
00132     new_ext->es = DESC_DATA_USUARIO;
00133     new_ext->fs = DESC_DATA_USUARIO;
00134     new_ext->gs = DESC_DATA_USUARIO;
00135     
00136     new_task->esp0 = (new_task->esp0 & 0xfffff000) + PAGINA_SIZE - 64;
00137     
00138     // Copiar los contextos
00139     memcpy(new, current, sizeof (struct int_regs) );
00140 
00141     // Duplicar los indicadores de cantidad de paginas usadas por los segmentos
00142     new_task->num_code = actual->num_code;
00143     new_task->num_data = actual->num_data;
00144     new_task->num_stack = actual->num_stack;
00145    
00146     struct user_page *mem;
00147     mem = new_task->mcode = actual->mcode;
00148     
00149     //Mapear las direcciones del segmento de codigo en memoria virtual, e incrementar el contador de procesos (count)
00150     for ( i=0 ; i < new_task->num_code ; i++,mem=mem->next ) {
00151                 if ( kmapmem( mem->dir , mem->vdir , new_task->cr3 ,PAGE_PRES|PAGE_USER|PAGE_RW)!=OK ){
00152                     kprintf("Kmapmem TASK_TEXT error\n");
00153                     return -1;
00154                 }
00155                 mem->count++;
00156     }
00157 
00158     struct user_page *src = actual->mdata;
00159     struct user_page *dest;
00160 
00161     //Para datos y bss debo pedir memoria, copiar la del proceso actual en ella, y finalmente mapearla
00162     for( i=0  ;  i < new_task->num_data ;  i++) {
00163                 if (i==0)
00164                         dest = umalloc_page ( src->flags, src->vdir, new_task->cr3 );
00165                 else    {
00166                         dest->next = umalloc_page ( src->flags, src->vdir, new_task->cr3 );
00167                         dest = dest->next;
00168                 }
00169                 if (!dest) { //liberar
00170                     actual->err_no = ENOMEM;
00171                     return -1;
00172                 }
00173                 if (i==0)       //Apuntar el mdata al comienzo de la lista
00174                     new_task->mdata = dest;
00175 
00176                 // Copiar el Stack del padre
00177                 copy_page ( (void *)dest->dir, (void *)src->dir);
00178                 src = src->next;
00179     }
00180 
00181         // Pido lugar para las páginas de stack y las copio
00182     src = actual->mstack;
00183     for( i=0  ;  i < new_task->num_stack ;  i++) {
00184                 if (i==0)
00185                         dest = umalloc_page ( src->flags, src->vdir, new_task->cr3 );
00186                 else    {
00187                         dest->next = umalloc_page ( src->flags, src->vdir, new_task->cr3 );
00188                         dest = dest->next;
00189                 }
00190                 if (!dest) { //liberar
00191                     actual->err_no = ENOMEM;
00192                     return -1;
00193                 }
00194                 if (i==0)       //Apuntar el mdata al comienzo de la lista
00195                     new_task->mstack = dest;
00196 
00197                 copy_page ( (void *)dest->dir, (void *)src->dir);
00198                 src = src->next;
00199     }
00200 
00201         TASK_SIGNALS_ALLOC(new_task);
00202         memcpy(TASK_SIGNALS(new_task), TASK_SIGNALS(actual), sizeof(struct task_signals));
00203 
00204     new_task->pid = get_new_pid();
00205     TASK_PARENT(new_task) = actual;
00206         new_task->padre = actual;
00207 
00208 
00209         // Inicializo el header de la lista de hijos
00210         LIST_INIT (new_task->childs);
00211         // Me agrego en la lista de hijos de mi padre
00212         LIST_ADD_TAIL(actual->childs, brothers, new_task);
00213 
00214         // Inicializo el header de la lista de hijos zombies
00215 //      LIST_INIT (new_task->zombie_header);
00216         
00217     // Poner en eax del hijo un 0, para que tome 0 como el retorno de fork
00218     new_ext->eax = 0;
00219 
00220         // Despertamos la nueva tarea, recordemos que init_new_task crea las tareas en estado TASK_STOPPED
00221     despertar_task( new_task );
00222         sti();
00223 
00224     return (new_task->pid);
00225 }
00226 
00227 
00234 int sys_exec (char *nombre)
00235 {
00236 //      kprintf("Esta llamada al sistema no se encuentra disponible, por favor, utilizar execve\n");
00237 //}
00238 
00239 #ifdef RUNSTATS
00240                 long long counter;
00241 
00242                 if ( getvar("debugexec") == 2 ) {
00243                         rdtscl(counter);
00244                 }
00245 #endif
00246         
00247 
00248     nombre = convertir_direccion( nombre , actual->cr3_backup);
00249  
00250     int fd;
00251     byte buff_aux[100];     //WARNING, agota el stack
00252     word i;
00253     
00254     struct coff_header *p;
00255     struct coff_sections sec_text, sec_data, sec_bss;
00256 
00257     int bytes_leidos;
00258     
00259     fd = open(nombre);
00260     if (fd < 0) {
00261                 actual->err_no = ENOENT;
00262         return -1;
00263     }
00264     
00265     // Leer cabecera basica del COFF32
00266     read(fd, buff_aux, sizeof(struct coff_header));
00267     p = (struct coff_header *) buff_aux;
00268 
00269     if (p->f_magic != COFF32_TYPE) {        // Verificar numero magico
00270                 actual->err_no = ENOEXEC;
00271                 close(fd);
00272                 return -1;
00273     }
00274     byte num_secciones;
00275     if ( (num_secciones = p->f_nscns)!= 3) {
00276                 actual->err_no = ENOEXEC;
00277                 close(fd);
00278                 return -1;
00279     }
00280     // Pararse donde comienzan las estructuras de las secciones ( header + datos_opcionales)
00281     lseek (fd, sizeof(struct coff_header) + p->f_opthdr , SEEK_SET);
00282 
00283     word verificacion = 0;      // Flag usado para verificar la existencia de .TEXT, .DATA y .BSS
00284 
00285     struct coff_sections *q;
00286     //Levantar las 3 secciones que debe tener el ejecutable
00287     while (num_secciones--) {
00288                 read(fd, buff_aux, sizeof(struct coff_sections));
00289                 q = (struct coff_sections *) buff_aux;
00290     
00291                 if ( q->s_flags == COFF32_TEXT ) {
00292                     memcpy ( &sec_text , q , sizeof(struct coff_sections) );
00293                     verificacion = verificacion | COFF32_TEXT;
00294                 }
00295                 else if ( q->s_flags == COFF32_DATA ) {
00296                     memcpy ( &sec_data , q , sizeof(struct coff_sections) );
00297                     verificacion = verificacion | COFF32_DATA;
00298                 }
00299                 else if ( q->s_flags == COFF32_BSS ) {
00300                     memcpy ( &sec_bss , q , sizeof(struct coff_sections) );
00301                     verificacion = verificacion | COFF32_BSS;
00302                 }
00303                 else {      //No se puede identificar el tipo de seccion
00304                     close(fd);
00305                     actual->err_no = ENOEXEC;
00306                     return -1;
00307                 }
00308     }
00309                     
00310     //Verificar que posea una seccion de codigo, una de datos inicializados y sin inicializar
00311     if (verificacion != (COFF32_TEXT | COFF32_DATA | COFF32_BSS) ) {
00312         close(fd);
00313                 actual->err_no = ENOEXEC;
00314                 return -1;
00315     }
00316     
00317     //Verificar que haya memoria suficiente    
00318     if (kmem_free() < ((actual->open_files[fd]->size / PAGINA_SIZE)+8) ) {
00319                 actual->err_no = ENOMEM;
00320                 close(fd);
00321                 return -1;
00322     }
00323 
00324     // Aca voy a guardar la cantidad de paginas requeridas por cada segmento
00325     word paginas_texto, paginas_datos;
00326 
00327     paginas_texto = sec_text.s_size / PAGINA_SIZE;
00328     if ( sec_text.s_size % PAGINA_SIZE ) {
00329                 paginas_texto++;
00330         }
00331     //Tamaño en bytes del .DATA + .BSS
00332     int size_datos = sec_data.s_size + sec_bss.s_size;
00333 
00334     //Cantidad de paginas requeridas por .DATA + .BSS
00335     paginas_datos = size_datos / PAGINA_SIZE;
00336     if ( size_datos % PAGINA_SIZE )
00337                 paginas_datos++;
00338 
00339         paginas_datos++;                // Uso una pagina de datos para (argc, **argv, **env) y llamada implicita a EXIT
00340         
00341     //Cantidad de paginas requeridas solo por .DATA
00342     int paginas_data = sec_data.s_size / PAGINA_SIZE;
00343     if ( sec_data.s_size % PAGINA_SIZE )
00344                 paginas_data++;
00345 
00346 
00347     task_struct_t *new_task;
00348     struct user_page *mem;
00349     
00350     // Poner el nombre de archivo como descripcion
00351     char nuevo_nombre[13];
00352     tomar_nombre_tarea(nombre, nuevo_nombre);
00353 
00354     // init_new_task devuelve la tarea creada como TASK_STOPPED, la mantendremos así hasta el final    
00355     new_task = init_new_task(DESC_CODE_USUARIO, DESC_DATA_USUARIO, TASK_TEXT, TASK_STACK + 4096 - 16, 0x202,\
00356                     nuevo_nombre, START_PRIORITY);
00357         
00358     if (!new_task) {        //liberar
00359                 return -1;
00360     }
00361 
00362     new_task->mstack = umalloc_page (PAGINA_STACK, TASK_STACK, new_task->cr3);
00363     if (!new_task->mstack)  //liberar
00364                 return -1;
00365 
00366         new_task->num_code = paginas_texto;
00367     new_task->num_data = paginas_datos;
00368     new_task->num_stack = 1;
00369     
00370     // Levantar el .TEXT
00371     lseek(fd, sec_text.s_scnptr,SEEK_SET);
00372     new_task->mcode = umalloc_page (PAGINA_CODE,TASK_TEXT, new_task->cr3);
00373     if (!new_task->mcode)    //liberar
00374                 return -1;
00375     mem = new_task->mcode;
00376     bytes_leidos =  read( fd, (void *)mem->dir, PAGINA_SIZE);
00377         
00378     for( i=1 ;  i < paginas_texto ; i++) {
00379                 mem->next = umalloc_page (PAGINA_CODE, TASK_TEXT + (i*PAGINA_SIZE) , new_task->cr3);
00380                 mem = mem->next;
00381         bytes_leidos =  read(fd, (void *)mem->dir , PAGINA_SIZE);
00382                 if (bytes_leidos < 0) {     //error de algo.... liberar memoria
00383                     actual->err_no = EIO;
00384                     close(fd);
00385                     return -1;
00386                 }
00387     }
00388 
00389     //Pedir memoria para los datos (.DATA + .BSS)
00390     new_task->mdata = umalloc_page (PAGINA_DATA, TASK_DATA, new_task->cr3);
00391     if (!new_task->mdata)   //liberar
00392                 return -1;
00393     for ( mem=new_task->mdata,i=1 ; i<paginas_datos ; i++, mem=mem->next ) {
00394         mem->next = umalloc_page (PAGINA_DATA, TASK_DATA + (i*PAGINA_SIZE) , new_task->cr3);
00395                 if (!mem->next)     //liberar
00396                     return -1;
00397     }
00398 
00399     //Levantar .DATA
00400     lseek(fd, sec_data.s_scnptr,SEEK_SET);
00401     for( i=0, mem=new_task->mdata ;   i < paginas_data  ;  i++, mem=mem->next ) {
00402                 bytes_leidos =  read(fd, (void *)mem->dir, PAGINA_SIZE);
00403                 if (bytes_leidos < 0) {     //error de algo.... liberar memoria
00404                     actual->err_no = EIO;
00405                     close(fd);
00406                     return -1;
00407                 }
00408     };
00409 
00410         // En esa página extra que pedimos para datos, vamos a ubicar una llamada a EXIT
00411         // y los argumentos de main y variables de entorno que recibe la tarea
00412         // Me ubico en la ultima pagina (la cual usare para exit, argv, etc, etc)
00413 
00414     for( mem=new_task->mdata ;  mem->next  ;  mem=mem->next);
00415 
00416         unsigned char *ptr_exit = (unsigned char *) mem->dir;
00417         
00418         // Ubicamos en el wrapper el codigo de libreria routstd de llamada EXIT:
00419         *ptr_exit = 0xb8;       // Codigo de operacion: "mov eax, "
00420         *(unsigned long *)(ptr_exit+1) = SYS_PROCESS | SYS_EXIT; 
00421         *(ptr_exit+5) = 0xbb; // "mov ebx, "
00422         *(unsigned long *)(ptr_exit+6) = 0; // parametro que recibe la función EXIT... 0 en este caso
00423         *(ptr_exit+10) = 0xcd;  // int
00424         *(ptr_exit+11) = 0x50;  // 0x50
00425 
00426         // Hardcodeo la llamada al sistema sys_signal_check, la cuál se ejecutará luego de cada handler de seña
00427         *(ptr_exit+12) = 0xb8;  // Codigo de operacion: "mov eax, "
00428         *(unsigned long *)(ptr_exit+13) = SYS_SIGNALS | SYS_SIGNAL_CHECK; 
00429         *(ptr_exit+17) = 0xcd;  // int
00430         *(ptr_exit+18) = 0x50;  // 0x50
00431         *(ptr_exit+19) = 0x5e;  // pop esi      // Con estos popeos recupero los registros de propósito general
00432         *(ptr_exit+20) = 0x5f;  // pop edi  // que fueron pusheados antes de ejecutar un handler de señal
00433         *(ptr_exit+21) = 0x5a;  // pop edx
00434         *(ptr_exit+22) = 0x59;  // pop ecx
00435         *(ptr_exit+23) = 0x5b;  // pop ebx
00436         *(ptr_exit+24) = 0x58;  // pop eax
00437         *(ptr_exit+25) = 0xc3;  // retn
00438 
00439         // Aloco la estructura que almacena info de señales
00440         TASK_SIGNALS_ALLOC(new_task);
00441         memset (TASK_SIGNALS(new_task), 0, sizeof(struct task_signals));
00442         TASK_SIGADDR(new_task) = GET_OFFSET(ptr_exit + 12) + mem->vdir;
00443 
00444 //      new_task->sigcheck_addr = GET_OFFSET(ptr_exit + 12) + mem->vdir;
00445  
00446 // Argumentos y demas facturetas        
00447         unsigned int argc = 0;
00448         char **argv, **envp;
00449 
00450         argv = NULL;
00451         envp = NULL;
00452         
00453         // Mando al fondo del Stack a envp
00454         unsigned long *qwe = (unsigned long *) (new_task->mstack->dir + 4096 - 4);
00455         *(qwe--) = (unsigned long) envp;
00456         *(qwe--) = (unsigned long) argv;
00457         *(qwe--) = (unsigned long) argc;
00458         *qwe = (unsigned long) mem->vdir;
00459 
00460         if (actual==pre_init_task) {                            // Si el proceso es init, caso particular ya que init no tiene formato de tarea
00461             TASK_PARENT(new_task) = actual;
00462                 new_task->pid = get_new_pid();
00463                 new_task->padre = pre_init_task;
00464                 // A los procesos que "executa init" le inicializo la lista de hijos, ya que no la van a reemplazar
00465                 // a init
00466                 LIST_INIT (new_task->childs);
00467                 // Agregarse como hijo de init
00468                 LIST_ADD (actual->childs, brothers, new_task);
00469         }
00470         else {                                                          // Si es cualquier otro proceso, el nuevo proceso debe heredar su pid y ppid
00471             TASK_PARENT(new_task) = TASK_PARENT(actual);
00472             new_task->pid = actual->pid;
00473                 new_task->padre = actual->padre;
00474                 // El nuevo proceso se hace cargo de todos los hijos
00475 //              new_task->zombie_header = actual->zombie_header;
00476                 //LIST_REPLACE(brothers, actual, new_task);
00477 //              START_TICKS_COUNT();
00478                 LIST_DEL(actual->padre->childs, brothers, actual);
00479                 LIST_ADD_TAIL(actual->padre->childs, brothers, new_task);
00480 //              END_TICKS_COUNT();
00481 //              PRINT_TICKS_COUNT();
00482         }
00483 
00484     close(fd);
00485 
00486     // Despertamos la nueva tarea, recordemos que init_new_task crea las tareas en estado TASK_STOPPED
00487     despertar_task( new_task );
00488 
00489 #ifdef RUNSTATS
00490   if ( getvar("debugexec") == 2 ) {
00491                 long long int counterfinal;
00492                 rdtscl(counterfinal);
00493                 kprintf("0x%llx ",counterfinal-counter);
00494         }       
00495 #endif
00496 
00497         // Recordemos que el proceso que ejecuto el exec debe terminar (excepto que sea el init)
00498         if (actual->pid!=1) {
00499 
00500                 cli();
00501                 sys_exit_mm();                                  // libero la memoria
00502                 remover_task (actual);                  // lo saco de la lista de tareas del scheduler
00503                 kfree_page ((addr_t)actual);    // libero el task_struct
00504                 sti();
00505                 _reschedule();                                  
00506         }
00507 
00508         
00509     return OK;
00510 }
00511 
00512 
00513 
00514 
00516 void sys_perror (char *str)
00517 {
00518     str = convertir_direccion( str , actual->cr3_backup);
00519     perror(str);
00520 }
00521 
00526 int sys_renice (word pid, word prioridad)
00527 {
00528 //    kprintf("TEMP SYS_RENICE. PID: %d\tPRI: %d\n", pid, prioridad);
00529     task_struct_t *tmp;
00530     if ( (tmp = encontrar_proceso_por_pid(pid))==NULL ) {
00531                 actual->err_no = ESRCH;
00532                 return -1;
00533     }
00534     // Esto es solo a modo de prueba ya que en routix por ahora el TASK_STOPPED cumple las veces de TASK_INTERRUMIPLE
00535     if (prioridad < 1)
00536                 dormir_task(tmp);
00537     tmp->prioridad = prioridad;    
00538     return OK;
00539 }
00540 
00542 inline pid_t sys_get_pid (void)
00543 {
00544     return actual->pid;
00545 }
00546 
00548 inline pid_t sys_get_ppid (void)
00549 {
00550     return TASK_PPID(actual);
00551 }
00552 
00554 //      Llamada al sistema Exit y funciones relacionadas
00555 //
00557 
00559 int zombie_queue_len = 0;
00560 
00561 
00567 /*
00568  *  \relates    sys_exit_notify
00569  *  \relates    sys_exit_mm
00570  *  \relates    sys_wait
00571  */
00572 void sys_exit (int valor)
00573 {
00574         cli();
00575         actual->retorno = valor;        
00576         
00577         sys_exit_mm();
00578         sys_exit_notify();
00579         sys_exit_fs();
00580         dormir_task(actual);
00581         actual->estado = TASK_ZOMBIE;
00582         sti();
00583         _reschedule();
00584 } 
00585 
00588 int sys_exit_mm(void)
00589 {
00590         // Libero la memoria utilizada por los handlers de señales (antes esto lo ejcutaba al final de esta función
00591         // y a veces me cagaba todo.... averiguar porque !!!
00592         TASK_SIGNALS_FREE(actual);
00593         
00594 
00595         struct user_page *aux, *tmp;
00596         // Liberar las paginas de código
00597         for (aux=tmp=actual->mcode ; aux && tmp ; aux=tmp) {
00598                 tmp=aux->next;
00599                 // Desmapear la direccion fisica de la logica
00600                 kunmapmem(aux->vdir, actual->cr3_backup);
00601                 // Si Esta habilitada la variable de entorno "__exit", imprimir info
00602                 if (getvar("__exit")==1)
00603                         kprintf("Liberando Codigo dir: 0x%x\tvdir: 0x%x\n", aux->dir,aux->vdir);
00604                 ufree_page(aux);
00605         }
00606         // Liberar de esta tarea las paginas de datos
00607         for (aux=tmp=actual->mdata ; aux && tmp ; aux=tmp) {
00608                 tmp=aux->next;
00609                 kunmapmem(aux->vdir, actual->cr3_backup);
00610                 if (getvar("__exit")==1)
00611                         kprintf("Liberando Datos dir: 0x%x\tvdir: 0x%x\n", aux->dir,aux->vdir);
00612                 ufree_page(aux);
00613         }
00614         // Liberar de esta tarea las paginas de codig
00615         for (aux=tmp=actual->mstack ; aux && tmp ; aux=tmp) {
00616                 tmp=aux->next;
00617                 kunmapmem(aux->vdir, actual->cr3_backup);
00618                 if (getvar("__exit")==1)
00619                         kprintf("Liberando Stack dir: 0x%x\tvdir: 0x%x\n", aux->dir,aux->vdir);
00620                 ufree_page(aux);
00621         }
00622         // Desmapear del directorio la pagina usada para los wrappers (de exit por ej)
00623         kunmapmem (TASK_TEXT - PAGINA_SIZE, actual->cr3_backup);
00624 
00625 
00626         // Libero el directorio de páginas utilizado por la tarea
00627         kfree_page (actual->cr3_backup);
00628         return 0;
00629 }
00630 
00635 int sys_exit_notify (void)
00636 {
00637         // Aumento la cuenta que lleva el sistema sobre zombies (proposito de debug)
00638         zombie_queue_len++;
00639 
00640         int value;
00641         pid_t pid;
00642         task_struct_t *child, *aux;
00643         // Tomar la condición de salida de mis hijos zombies
00644         _LIST_FOREACH(child, actual->childs, brothers) {
00645                 aux = LIST_NEXT(brothers, child);
00646                 
00647                 // Si el proceso está zombie, tomo su condidción de salida y lo libero
00648                 if (child->estado == TASK_ZOMBIE)       {
00649                         if (getvar("exit")==1)
00650                                 kprintf("Esperando al hijo: %d\n", child->pid);
00651                         // Liberar el primer hijo que se encuentre
00652                         pid = sys_waitpid(-1,&value,WNOHANG);
00653                         
00654                         if (getvar("exit")==1)
00655                                 kprintf("EXIT_NOTIFY: termino hijo %d con: %d\n", pid, value);
00656                 }
00657                 // Si está en otro estado, se lo paso a init
00658                 else {
00659                         LIST_DEL(actual->childs, brothers, child);
00660                         LIST_ADD_TAIL(init_task->childs, brothers, child);
00661                         child->padre = init_task;
00662                 }
00663                 
00664                 child = aux;
00665         }
00666         // Envio la señal SIGCHLD al padre
00667         _sys_kill(actual->padre, SIGCHLD);
00668 
00669         // Despertar a init     
00670         wakeup_init();
00671         return 0;
00672 } 
00673 
00676 int sys_exit_fs ()
00677 {
00678         int i;
00679     for (i=0 ; i < MAX_FILES_POR_TAREA ; i++)
00680                 if (actual->open_files[i]) {
00681                         free(actual->open_files[i]);
00682                         file_free++;
00683                 }
00684 
00685         return 0;
00686 }
00687 
00688 
00694 pid_t sys_waitpid (pid_t pid, int *status, int options)
00695 {
00696         _cli();
00697     status = convertir_direccion( status , actual->cr3_backup);
00698 
00699         struct task_struct_t *child;
00700 
00701         int zombie_found = 0;
00702 
00703         while (1) {
00704                 // Recorrer la lista de procesos hijos, en busca de zombies
00705                 LIST_FOREACH (child, actual->childs, brothers) {
00706                         // Si el hijo no es zombie, seguir buscando
00707                         if (TASK_STATE(child)!=TASK_ZOMBIE)
00708                                 continue;
00709                         // Buscar cualquier hijo (pid=-1) o alguno en particular (pid>1)?       
00710                         if (pid>1  &&  pid!=TASK_PPID(child))
00711                                 break;
00712                         zombie_found = 1;
00713                         break;
00714                 }
00715                 if (zombie_found==1)    
00716                         break;
00717                 if (getvar("__wait")==1)
00718                         kprintf("SYS_WAIT: Mi PID es: %d\tNo encontre hijo zombie\n", actual->pid);
00719 
00720                 // Si es no bloqueante, debo irme con -1 al no haberlo encontrado
00721                 if (options==WNOHANG)   {               
00722                         if (getvar("__wait")==1)
00723                                 kprintf("SYS_WAIT: Me voy por el WNOHANG....\n");
00724                         actual->err_no = ECHILD;
00725                         _sti();
00726                         return -1;
00727                 }
00728                 _sti();
00729                 _reschedule();  // espero un rato
00730                 _cli();
00731         }
00732         
00733         // Mientras que aux queda apuntando al nodo anterior, tmp lo hace al nodo en cuestión
00734         pid_t child_pid = TASK_PID(child);
00735         if (getvar("__wait")==1) 
00736                 kprintf("SYS_WAIT:Mi hijo zombie es: %d\n", child->pid);
00737 
00738         // Valor de retorno del hijo
00739         *status = child->retorno;
00740         remover_task (child);
00741         
00742         // Quitar al nodo de la lista
00743         LIST_DEL (actual->childs,brothers, child);
00744         
00745         // Liberar el task struct utilizado
00746         kfree_page ((addr_t)child);
00747 //      free (aux);
00748         zombie_queue_len--;
00749         
00750         _sti();
00751         return child_pid;
00752 }
00753 
00754 
00755 
00756 //Cantidad de veces que la función malloc llamo a morecore solicitandole una página
00757 extern word morecores;
00758 extern struct floppy_cache *header_floppy_cache;
00759 
00760 void *punteros[1000];
00761 
00765 void sys_show (int valor)
00766 {
00767         int xx;
00768         int mem_before = kmem_free();
00769         int veces;
00770         int i;
00771         switch (valor) {
00772                 case 1: 
00773                         kprintf ("Cantidad de paginas asignadas via Morecores: %d\n", morecores);
00774                         break;
00775                 case 2:
00776                         kprintf("Sectores en cache: ");
00777                         struct floppy_cache *aux;
00778                         for (aux = header_floppy_cache, i=0 ; aux ; aux=aux->next, i++)
00779                                 kprintf("%d ", aux->sector);
00780                         kprintf("\nSizeof floppy_cache: %d\n", sizeof(struct floppy_cache));
00781                         kprintf("Sectores cacheados: %d\tPaginas usadas: %d\n", i, sizeof(struct floppy_cache) * i / 4096 + 1);
00782                         break;
00783                 case 3:
00784                         kprintf ("Cantidad de procesos zombies: %d\n", zombie_queue_len);
00785                         break;
00786                 case 4:
00787                         if ((veces=getvar("veces"))==-1)
00788                                 veces = 10;
00789 
00790                         for (xx=0 ; xx<veces ; xx++) {
00791                                 if ((punteros[xx]=malloc(300))==NULL) {
00792                                         kprintf("MALLOC ERROR\n");
00793                                         return;
00794                                 }
00795                         }
00796                         
00797                         for (xx=0 ; xx<veces ; xx++) {
00798                                 free(punteros[xx]);
00799                         }
00800                         
00801                         kprintf("Veces: %d\tMemoria antes: %d\tdespues: %d\n", veces, mem_before, kmem_free());
00802                         break;
00803 
00804                 case 5:
00805                         num_mallocs = num_frees = 0;
00806                         task_signals_alloc = task_signals_free = 0;
00807                         umalloc_alloc = umalloc_free = 0;
00808                         file_alloc = file_free = 0;
00809                         break;
00810                 case 6:
00811                         kprintf("Cantidad de Mallocs: %d\tFrees: %d\n", num_mallocs, num_frees);
00812                         kprintf("Allocs de task_Signals: %d\tFrees: %d\n", task_signals_alloc, task_signals_free);
00813                         kprintf("Allocs de User_page: %d\tFrees: %d\n", umalloc_alloc, umalloc_free);
00814                         kprintf("Allocs de File: %d\tFrees: %d\n", file_alloc, file_free);
00815                         break;
00816                 case 7:
00817                         task_signals_alloc = task_signals_free = 0;
00818                         break;
00819                 case 8:
00820                         kprintf("Cantidad de Mallocs de task_Signals: %d\tFrees: %d\n", task_signals_alloc, task_signals_free);
00821                         break;
00822                 default:
00823 
00824                         break;
00825         }
00826                         
00827 }
00828 
00829 
00830 
00831 
00840 int sys_execve (char *nombre, char **arg_p, char **env_p)
00841 {
00842     nombre = convertir_direccion( nombre , actual->cr3_backup);
00843  
00844     int fd;
00845     byte buff_aux[100];     //WARNING, agota el stack
00846     word i;
00847     
00848     struct coff_header *p;
00849     struct coff_sections sec_text, sec_data, sec_bss;
00850 
00851     int bytes_leidos;
00852     
00853     fd = open(nombre);
00854     if (fd < 0) {
00855                 actual->err_no = ENOENT;
00856         return -1;
00857     }
00858 
00859     // Leer cabecera basica del COFF32
00860     read(fd, buff_aux, sizeof(struct coff_header));
00861     p = (struct coff_header *) buff_aux;
00862 
00863     if (p->f_magic != COFF32_TYPE) {        // Verificar numero magico
00864                 actual->err_no = ENOEXEC;
00865                 close(fd);
00866                 return -1;
00867     }
00868     byte num_secciones;
00869     if ( (num_secciones = p->f_nscns)!= 3) {
00870                 actual->err_no = ENOEXEC;
00871                 close(fd);
00872                 return -1;
00873     }
00874     // Pararse donde comienzan las estructuras de las secciones ( header + datos_opcionales)
00875     lseek (fd, sizeof(struct coff_header) + p->f_opthdr , SEEK_SET);
00876 
00877     word verificacion = 0;      // Flag usado para verificar la existencia de .TEXT, .DATA y .BSS
00878 
00879     struct coff_sections *q;
00880     //Levantar las 3 secciones que debe tener el ejecutable
00881     while (num_secciones--) {
00882                 read(fd, buff_aux, sizeof(struct coff_sections));
00883                 q = (struct coff_sections *) buff_aux;
00884     
00885                 if ( q->s_flags == COFF32_TEXT ) {
00886                     memcpy ( &sec_text , q , sizeof(struct coff_sections) );
00887                     verificacion = verificacion | COFF32_TEXT;
00888                 }
00889                 else if ( q->s_flags == COFF32_DATA ) {
00890                     memcpy ( &sec_data , q , sizeof(struct coff_sections) );
00891                     verificacion = verificacion | COFF32_DATA;
00892                 }
00893                 else if ( q->s_flags == COFF32_BSS ) {
00894                     memcpy ( &sec_bss , q , sizeof(struct coff_sections) );
00895                     verificacion = verificacion | COFF32_BSS;
00896                 }
00897                 else {      //No se puede identificar el tipo de seccion
00898                     close(fd);
00899                     actual->err_no = ENOEXEC;
00900                     return -1;
00901                 }
00902     }
00903                     
00904     //Verificar que posea una seccion de codigo, una de datos inicializados y sin inicializar
00905     if (verificacion != (COFF32_TEXT | COFF32_DATA | COFF32_BSS) ) {
00906         close(fd);
00907                 actual->err_no = ENOEXEC;
00908                 return -1;
00909     }
00910     
00911     //Verificar que haya memoria suficiente    
00912     if (kmem_free() < ((actual->open_files[fd]->size / PAGINA_SIZE)+8) ) {
00913                 actual->err_no = ENOMEM;
00914                 close(fd);
00915                 return -1;
00916     }
00917 
00918     // Aca voy a guardar la cantidad de paginas requeridas por cada segmento
00919     word paginas_texto, paginas_datos;
00920 
00921     paginas_texto = sec_text.s_size / PAGINA_SIZE;
00922     if ( sec_text.s_size % PAGINA_SIZE ) {
00923                 paginas_texto++;
00924         }
00925     //Tamaño en bytes del .DATA + .BSS
00926     int size_datos = sec_data.s_size + sec_bss.s_size;
00927 
00928     //Cantidad de paginas requeridas por .DATA + .BSS
00929     paginas_datos = size_datos / PAGINA_SIZE;
00930     if ( size_datos % PAGINA_SIZE )
00931                 paginas_datos++;
00932 
00933         paginas_datos++;                // Uso una pagina de datos para (argc, **argv, **env) y llamada implicita a EXIT
00934         
00935     //Cantidad de paginas requeridas solo por .DATA
00936     int paginas_data = sec_data.s_size / PAGINA_SIZE;
00937     if ( sec_data.s_size % PAGINA_SIZE )
00938                 paginas_data++;
00939 
00940     task_struct_t *new_task;
00941     struct user_page *mem;
00942     
00943     // Poner el nombre de archivo como descripcion
00944     char nuevo_nombre[13];
00945     tomar_nombre_tarea(nombre, nuevo_nombre);
00946 
00947     // init_new_task devuelve la tarea creada como TASK_STOPPED, la mantendremos así hasta el final    
00948     new_task = init_new_task(DESC_CODE_USUARIO, DESC_DATA_USUARIO, TASK_TEXT, TASK_STACK + 4096 - 16, 0x202,\
00949                     nuevo_nombre, START_PRIORITY);
00950         
00951     if (!new_task) {        //liberar
00952                 return -1;
00953     }
00954 
00955     new_task->mstack = umalloc_page (PAGINA_STACK, TASK_STACK, new_task->cr3);
00956     if (!new_task->mstack)  //liberar
00957                 return -1;
00958 
00959         new_task->num_code = paginas_texto;
00960     new_task->num_data = paginas_datos;
00961     new_task->num_stack = 1;
00962     
00963     // Levantar el .TEXT
00964     lseek(fd, sec_text.s_scnptr,SEEK_SET);
00965     new_task->mcode = umalloc_page (PAGINA_CODE,TASK_TEXT, new_task->cr3);
00966     if (!new_task->mcode)    //liberar
00967                 return -1;
00968     mem = new_task->mcode;
00969     bytes_leidos =  read( fd, (void *)mem->dir, PAGINA_SIZE);
00970         
00971     for( i=1 ;  i < paginas_texto ; i++) {
00972                 mem->next = umalloc_page (PAGINA_CODE, TASK_TEXT + (i*PAGINA_SIZE) , new_task->cr3);
00973                 mem = mem->next;
00974         bytes_leidos =  read(fd, (void *)mem->dir , PAGINA_SIZE);
00975                 if (bytes_leidos < 0) {     //error de algo.... liberar memoria
00976                     actual->err_no = EIO;
00977                     close(fd);
00978                     return -1;
00979                 }
00980     }
00981 
00982     //Pedir memoria para los datos (.DATA + .BSS)
00983     new_task->mdata = umalloc_page (PAGINA_DATA, TASK_DATA, new_task->cr3);
00984     if (!new_task->mdata)   //liberar
00985                 return -1;
00986     for ( mem=new_task->mdata,i=1 ; i<paginas_datos ; i++, mem=mem->next ) {
00987         mem->next = umalloc_page (PAGINA_DATA, TASK_DATA + (i*PAGINA_SIZE) , new_task->cr3);
00988                 if (!mem->next)     //liberar
00989                     return -1;
00990     }
00991 
00992     //Levantar .DATA
00993     lseek(fd, sec_data.s_scnptr,SEEK_SET);
00994     for( i=0, mem=new_task->mdata ;   i < paginas_data  ;  i++, mem=mem->next ) {
00995                 bytes_leidos =  read(fd, (void *)mem->dir, PAGINA_SIZE);
00996                 if (bytes_leidos < 0) {     //error de algo.... liberar memoria
00997                     actual->err_no = EIO;
00998                     close(fd);
00999                     return -1;
01000                 }
01001     };
01002 
01003         // **** A partir de aqui se ubica al fondo del stack el envp, argv, argc y el retorno del main **** //
01004         
01005         // Me ubico en la ultima pagina (la cual usare para exit, argv, etc, etc)
01006     for( mem=new_task->mdata ;  mem->next  ;  mem=mem->next);
01007         
01008         unsigned char *ptr_exit = (unsigned char *) mem->dir;
01009         
01010         // Ubicamos en el wrapper el codigo de libreria routstd de llamada EXIT:
01011         *ptr_exit = 0xb8;       // Codigo de operacion: "mov eax, "
01012         *(unsigned long *)(ptr_exit+1) = SYS_PROCESS | SYS_EXIT; 
01013         *(ptr_exit+5) = 0xbb; // "mov ebx, "
01014         *(unsigned long *)(ptr_exit+6) = 0; // parametro que recibe la función EXIT... 0 en este caso
01015         *(ptr_exit+10) = 0xcd;  // int
01016         *(ptr_exit+11) = 0x50;  // 0x50
01017         
01018         // Hardcodeo la llamada al sistema sys_signal_check, la cuál se ejecutará luego de cada handler de seña
01019         *(ptr_exit+12) = 0xb8;  // Codigo de operacion: "mov eax, "
01020         *(unsigned long *)(ptr_exit+13) = SYS_SIGNALS | SYS_SIGNAL_CHECK; 
01021         *(ptr_exit+17) = 0xcd;  // int
01022         *(ptr_exit+18) = 0x50;  // 0x50
01023         *(ptr_exit+19) = 0x5e;  // pop esi      // Con estos popeos recupero los registros de propósito general
01024         *(ptr_exit+20) = 0x5f;  // pop edi  // que fueron pusheados antes de ejecutar un handler de señal
01025         *(ptr_exit+21) = 0x5a;  // pop edx
01026         *(ptr_exit+22) = 0x59;  // pop ecx
01027         *(ptr_exit+23) = 0x5b;  // pop ebx
01028         *(ptr_exit+24) = 0x58;  // pop eax
01029         *(ptr_exit+25) = 0xc3;  // retn
01030         
01031         TASK_SIGNALS_ALLOC(new_task);
01032         memset (TASK_SIGNALS(new_task), 0, sizeof(struct task_signals));
01033         TASK_SIGADDR(new_task) = GET_OFFSET(ptr_exit + 12) + mem->vdir;
01034         
01035         #define EXIT_CALL_LEN           12
01036         #define SIGNAL_CHECK_LEN        14
01037         
01038         // Traspaso de argumentos y variables de entorno
01039         arg_p = convertir_direccion(arg_p, actual->cr3_backup);
01040         env_p = convertir_direccion(env_p, actual->cr3_backup);
01041 
01042         char **argv, **envp; 
01043         // Cantidad de argumentos, más el nombre del ejecutable
01044         int argc = count_elements (arg_p) + 1;
01045         // Cantidad de variables de entorno seteadas
01046         int envc = count_elements (env_p);
01047 
01048         char *aux_dest;
01049         argv = (char **) ptr_exit + EXIT_CALL_LEN + SIGNAL_CHECK_LEN;
01050         aux_dest = (char *)(argv + argc + 1);                   // Empiezo a poner los strings despues del vector de punteros argv
01051         strcpy(aux_dest, nuevo_nombre);
01052         int z;
01053 
01054         for (z=0 ; z<argc ; z++) {
01055                 argv[z] = GET_OFFSET(aux_dest) + (char *) mem->vdir;
01056                 aux_dest += strlen(aux_dest) + 1;
01057                 strcpy(aux_dest, convertir_direccion(arg_p[z], actual->cr3_backup));
01058         }
01059         // Coloco el NULL como ultimo elemento de vector de punteros
01060         argv[z+2] = NULL;
01061 
01062         // Alinear a 4 bytes
01063         envp = (char **) ALINEAR_4(aux_dest + strlen(aux_dest) + 4);
01064 
01065         aux_dest = (char *) (envp + envc + 2);
01066         for (z=0 ; z<envc ; z++) {
01067                 strcpy(aux_dest, convertir_direccion(env_p[z], actual->cr3_backup));
01068                 envp[z] = GET_OFFSET(aux_dest) + (char *) mem->vdir;
01069                 aux_dest += strlen(aux_dest) + 1;
01070         }
01071         // Coloco el NULL como ultimo elemento de vector de punteros
01072         envp[z+1] = NULL;
01073         // TEMPORAL (no recuerdo porque le puse temporal !!!)
01074         argv = (char **)(GET_OFFSET(argv) + (char *) mem->vdir);
01075         envp = (char **)(GET_OFFSET(envp) + (char *) mem->vdir);
01076         
01077         // Mando al fondo del Stack a envp, argv, argc y el RET a sys_exit
01078         unsigned long *qwe = (unsigned long *) (new_task->mstack->dir + 4096 - 4);
01079         *(qwe--) = (unsigned long) envp;
01080         *(qwe--) = (unsigned long) argv;
01081         *(qwe--) = (unsigned long) argc;
01082         *qwe = (unsigned long) mem->vdir;
01083 /*
01084         // El nuevo proceso debe heredar el PID y el PPID del llamante, excepto que sea INIT
01085         if (actual->pid==1) {                           // Si el proceso es init, caso particular ya que init no tiene formato de tarea
01086             TASK_PARENT(new_task) = actual;
01087             TASK_PPID(new_task) = actual->pid;
01088                 new_task->pid = get_new_pid();
01089                 new_task->padre = init_task;
01090         }
01091         else {                                                          // Si es cualquier otro proceso, el nuevo proceso debe heredar su pid y ppid
01092             TASK_PARENT(new_task) = TASK_PARENT(actual);
01093             new_task->pid = actual->pid;
01094                 new_task->padre = actual->padre;
01095         }
01096 */
01097         if (actual==pre_init_task) {                            // Si el proceso es init, caso particular ya que init no tiene formato de tarea
01098             TASK_PARENT(new_task) = actual;
01099                 new_task->pid = get_new_pid();
01100                 new_task->padre = pre_init_task;
01101                 // A los procesos que "executa init" le inicializo la lista de hijos, ya que no la van a reemplazar
01102                 // a init
01103                 LIST_INIT (new_task->childs);
01104                 // Agregarse como hijo de init
01105                 LIST_ADD (actual->childs, brothers, new_task);
01106         }
01107         else {                                                          // Si es cualquier otro proceso, el nuevo proceso debe heredar su pid y ppid
01108             TASK_PARENT(new_task) = TASK_PARENT(actual);
01109             new_task->pid = actual->pid;
01110                 new_task->padre = actual->padre;
01111                 // El nuevo proceso se hace cargo de todos los hijos
01112 //              new_task->zombie_header = actual->zombie_header;
01113                 //LIST_REPLACE(brothers, actual, new_task);
01114 //              START_TICKS_COUNT();
01115                 LIST_DEL(actual->padre->childs, brothers, actual);
01116                 LIST_ADD_TAIL(actual->padre->childs, brothers, new_task);
01117 //              END_TICKS_COUNT();
01118 //              PRINT_TICKS_COUNT();
01119         }
01120 
01121         
01122     close(fd);
01123 
01124     // Despertamos la nueva tarea, recordemos que init_new_task crea las tareas en estado TASK_STOPPED
01125     despertar_task( new_task );
01126 
01127         // Recordemos que el proceso que ejecuto el exec debe terminar (excepto que sea el init)
01128         if (actual->pid!=1) {
01129                 cli();
01130                 sys_exit_mm();                                  // libero la memoria
01131                 remover_task (actual);                  // lo saco de la lista de tareas del scheduler
01132                 kfree_page ((addr_t)actual);    // libero el task_struct
01133                 sti();
01134                 _reschedule();                                  
01135         }
01136     return OK;
01137 }
01138 
01140 inline int count_elements (char **vector)
01141 {
01142         int i;
01143         for ( i=0 ; vector[i]!=NULL && i<10 && vector; i++);
01144         return i;
01145 }

Generated on Sun May 30 18:38:35 2004 for Routix OS by doxygen 1.3.6