Lic.Graciela De Luca UNLAM. Lic.Graciela De Luca 2 Niveles en los Sistemas Operativos USUARIOS...
-
Upload
sence-carranco -
Category
Documents
-
view
3 -
download
0
Transcript of Lic.Graciela De Luca UNLAM. Lic.Graciela De Luca 2 Niveles en los Sistemas Operativos USUARIOS...
Lic.Graciela De Luca
UNLAM
Lic.Graciela De Luca 2
Niveles en los Sistemas OperativosUSUARIOS
PROGRAMAS DEL SISTEMA
INTERPRETE DE COMANDOS
UTILIDADES PARA PROCESOS
UTILIDADES PARA ARCHIVOS
LLAMADAS AL SISTEMA
SISTEMA OPERATIVO
Lic.Graciela De Luca 3
Systems Calls: Interfaz que ofrece el Sistema Operativo al resto de los programas que les permite solicitarle algún trabajo
Son servicios para: Interactuar con el Hardware Gestión de procesos Manejo de memoria Señales Tiempo Etc.
Los servicios se ofrecen por medio de Llamadas al Sistema (Sistem calls)
Las invoca un proceso de usuario y son servidas por el kernel
Lic.Graciela De Luca 4
Interfaces de los Sistemas Operativos Posix1
Posix es el nombre común del estandar IEEE1003.1:1996 Nos encontramos con la versión estándar de 1990 (sin hilos ):
Llamadas al sistema Funciones de C estandarizadas (Ansi C)
Surgió para estandarizar los sistemas Unix Permite código fuente portable Muchos sistemas cumplen con ella: UNIX , Linux, Windows
NT,VMS y Os2
Win32 Interfaz común a todos los sistemas de Microsoft Windows Ningún otro sistema cumple con ella
Lic.Graciela De Luca 5
Ventajas de la capa intermedia de llamadas al sistema Facilita la programación. No es necesario
conocer a fondo el HW Incrementa la seguridad del sistema, ya
que el kernel puede comprobar que los parámetros de la llamada al sistema son correctos antes de intentar servirla
Hace los programas más portables ya que usan interfaces comunes
Lic.Graciela De Luca 6
Llamadas al sistema y APIs
Es necesario resaltar la diferencia entre un API y el conjunto de llamadas al sistema API: Application Programming Interface, interfaz de
programación de aplicaciones. Dos niveles diferenciados
Llamadas al sistema API
Interfaz ofrecida para el programador por una biblioteca de funciones
Interfaz ofrecida por el kernel
Lic.Graciela De Luca 7
Interfaz con el sistema operativo Se pueden distinguir dos puntos de vista en la
interfaz ofrecida por las llamadas al sistema: La interfaz ofrecida por el núcleo del sistema
operativo. Es una interfaz definida a nivel de lenguaje ensamblador. Depende directamente del "hardware" sobre el cual se
está ejecutando el S.O La interfaz ofrecida al programador o usuario
(API). MSDOS
Documentada a nivel de ensamblador: Interrupción a la que hay que llamar, valores de los registros que hay que cargar y valores de retorno.
UNIX Funciones estándar en lenguaje C.
P.ej. int kill (pid_t pid, int sig);
Lic.Graciela De Luca 8
Interfaz ofrecida por el núcleo El núcleo de Linux, en IA32, utiliza la instrucción int 0x80 como puerta de
entrada en el núcleo. (win 32 usa Int 0x2E) El handler de la interrupción software se instala en la función trap_init() [
arch/i386/kernel/traps.c] El número de la interrupción software esta definido por la constante
SYSCALL_VECTOR [include/asm-i386/hw_irq.h#L19]
916 void __init trap_init (void) 917 { ... 922 923 set_trap_gate(0,÷_error); 924 set_trap_gate(1,&debug); 925 set_intr_gate(2,&nmi); 926 set_system_gate(3,&int3); /* int3-5 can be called from all */ 927 set_system_gate(4,&overflow); ... 943944 set_system_gate(SYSCALL_VECTOR,&system_call); 945 ... 963 }
Lic.Graciela De Luca 9
Interfaz ofrecida por el núcleo PARÁMETROS DE ENTRADA
Linux los pasa en los siguientes registros del procesador. %ebx arg 1%ecx arg 2%edx arg 3%esi arg 4%edi arg 5
Código del servicio requerido en el registro %eax. En el archivo include/asm-i386/unistd.h aparecen listadas todas
las llamadas al sistema que ofrece Linux con su correspondiente número.
VALORES DE SALIDA En el registro %eax se devuelve el código de retorno.
Lic.Graciela De Luca 10
Todas las implementaciones de UNIX disponen de unas bibliotecas de usuario que esconden la implementación concreta de las llamadas al sistema (la interfaz real ofrecida por el S.O.) y ofrecen al programador una interfaz C que presenta las siguientes ventajas: Facilidad de uso al acceder desde un lenguaje de alto nivel. Portabilidad entre arquitecturas: Linux-sparc, Linux-i386,
etc. Portabilidad entre diferentes versiones de UNIX: estándar
POSIX. El estándar POSIX se define sólo a nivel de interfaz, no a nivel de implementación real.
Documentación de llamadas al sistema: sección 2 del manual de UNIX ej.# man 2 kill
Interfaz ofrecida al programador (API)
Lic.Graciela De Luca 11
Llamadas al sistema y APIs EJ: La función fork() del Lenguaje C no realiza el
servicio fork , solo lo solicita al sistema operativo.Las funciones que solicitan servicios se componen de :
1. Una parte inicial que prepara los parámetros del servicio, tal como los espera el SO
2. La instrucción INT 0x80 que realiza el paso al SO
3. Una parte final que recoge los parámetros de contestación del SO para devolverlos al programa que hizo la llamada
Lic.Graciela De Luca 12
Proceso de llamada
Lic.Graciela De Luca 13
Proceso de llamada El proceso de usuario realiza una llamada a la función
del API correspondiente (wrapper routine)
La función del API prepara los parámetros de entrada y realiza una interrupción software, generando con ello la llamada al sistema. Esto eleva una excepción (0x80)
Se cambia a modo kernel y se ejecuta el manejador de excepción, en este caso de llamada al sistema (system call handler)
El manejador determina la llamada al sistema y llama a la función de servicio de la llamada al sistema (system call service routine)
Lic.Graciela De Luca 14
Llamadas al sistema y APIs En general, las llamadas al sistema estarán encapsuladas
en funciones del API de programación del sistema operativo Las funciones del API encapsulan llamadas al
sistema “rutinas envoltorio” (wrapper routines) No necesariamente todas las funciones del API
encapsulan llamadas al sistema. También, una función del API puede realizar varias
llamadas al sistema o varias funciones realizar la misma llamada con diferentes parámetros y funcionalidad añadida.
Estándar POSIX: interfase entre la API de programación y S.CALL, no es la implementación de la S.CALL
Las llamadas al sistema, pertenecen al kernel. Las funciones de biblioteca (API) son software a nivel
usuario.
Lic.Graciela De Luca 15
Biblioteca de llamadas al sistema libc contiene todas las llamadas al sistema
Oculta los detalles de la interfaz de las llamadas al sistema del núcleo en forma de funciones en C.
Las funciones trasladan los parámetros que reciben, normalmente a traves de la pila, en los registros del procesador apropiados, invocan al S.O., recogen el código de retorno (en la variable errno), etc.
Existen casos en los que dos llamadas al sistema de la biblioteca coinciden con la misma llamada al sistema "real" (P.Ej. waitpid y wait4 invocan ambas a la llamada al sistema wait4).
Lic.Graciela De Luca 16
Biblioteca de llamadas al sistema Algunas supuestas llamadas al sistema ofrecidas
por la biblioteca son implementadas completamente por ella misma (el núcleo del S.O. no se invoca)
Inicialmente, en Linux, la libc la mantenían Linus Torvalds et al.. Actualmente, se utiliza la biblioteca de GNU (glibc).
libc.a biblioteca estática
libc.so biblioteca dinámica
El código de la biblioteca NO pertenece al núcleo del S.O., sino que está en el espacio de direcciones del usuario.
Lic.Graciela De Luca 17
Código de retorno En la IA32, Linux devuelve el valor de
retorno de la S.Call en el registro %eax. Si no ha tenido éxito, el valor devuelto es
negativo. Si es negativo, la biblioteca copia dicho
valor sobre una variable global llamada errno y devuelve -1.
Algunas llamadas realizadas con éxito pueden devolver un valor negativo (p.ej. lseek).
Lic.Graciela De Luca 18
Código de retorno
El rango de errores se encuentra entre -1 y -4095 (0xfffff001).
La biblioteca debe ser capaz de determinar cuándo el valor devuelto es un error y tratarlo de forma adecuada.
La rutina syscall_error es la encargada de hacerlo. La variable errno contiene el código de error de la última
llamada que falló. Una llamada relizada con éxito no modifica errno. (#
man 3 errno) La variable errno está declarada en la propia biblioteca.
Lic.Graciela De Luca 19
Entrando en el núcleo La int 0x80 produce un salto a la. función
system_call (zona de código del S.O entry.S L187)
La interrupción 0x80 se asocia con la función system_call al inicializar Linux en la línea 943 de traps.c de la función trap_init() invocada desde la función start_kernel de main.c L545
Lic.Graciela De Luca 20
En el proceso de salto ...
El procesador pasa de modo usuario ("ring level" 3 en la IA32) a modo supervisor ("ring level" 0).
Se cambia el puntero de pila para que apunte a la pila del núcleo y se guardan en dicha pila algunos registros (SS, ESP, EFLAGS, CS, EIP).
En IA32 cada nivel de privilegio tiene un puntero de pila distinto por motivos de seguridad.
Lic.Graciela De Luca 21
Lic.Graciela De Luca 22
Dentro de system_call (entry.S )194 ENTRY(system_call) 195 pushl %eax # save orig_eax 196 SAVE_ALL 197 GET_CURRENT(%ebx) # save punt al PCB198 testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS 199 jne tracesys200 cmpl $(NR_syscalls),%eax 201 jae badsys # retorna con el cod error ENOSYS202 call *SYMBOL_NAME(sys_call_table)(,%eax,4) 203 movl %eax,EAX(%esp) # save valor de retorno 204 ENTRY(ret_from_sys_call) 205 cli # need_resched y testea señales
atomic 206 cmpl $0,need_resched(%ebx) 207 jne reschedule 208 cmpl $0,sigpending(%ebx)209 jne signal_return 210 restore_all:211 RESTORE_ALL
Lic.Graciela De Luca 23
1º guarda el código de la llamada al sistema en la pila del núcleo (entry.S#L195]).
2º A continuación es importante guardar todos los registros del procesador con la macro SAVE_ALL]) (entry.S#L85)
3º Se pone el puntero al PCB de la tarea actual en el registro %ebx (#197 ).
Lic.Graciela De Luca 24
4º Se verifica si el proceso padre está monitorizando este proceso (#198 ), en cuyo caso se ejecuta el código tracesys.
Para verificar algunas condiciones sobre el estado del proceso actual se accede a su PCB a través de su registro %ebx.
Para acceder a los campos de la estructura struct task_struct (sched.h#L281) se utilizan
desplazamientos fijos definidos al principio del archivo entry.S. [70-80]
Se puede ver la correspondencia en la propia estructura sched.h
Lic.Graciela De Luca 25
El código de tracesys informa al proceso padre de que su hijo está realizando una llamada al sistema, antes y después de servirla.
5ºSe comprueba que el número de llamada pedido es válido (si está dentro del rango). Si no es válido, se ejecuta el código de badsys [entry.S#L243] que retorna inmediatamente con el código de error ENOSYS. (entry.S [243-246])
Lic.Graciela De Luca 26
6º Se llama a la función que sirve la llamada pedida: 202 call *SYMBOL_NAME(sys_call_table)(,%eax,4) sys_call_table [entry.S#L397] es un vector de direcciones de salto que contiene las direcciones de la funciones que sirven cada una de las llamadas al sistema. Se utiliza el registro %eax como índice, teniendo en cuenta que cada dirección ocupa 4 bytes.
7º Finalmente se pone en el registro %eax el código de retorno, y se ejecuta el código de ret_from_sys_call [entry.S#L204].
Realmente se almacena el valor del registro %eax en la posición que ocupa dicho registro en la pila del núcleo EAX(%esp) (entry.S#L55).
Al comienzo del archivo entry.S se han definido constantes que permiten acceder a los registros almacenados en la pila utilizando el puntero %esp (entry.S [49-63])
Lic.Graciela De Luca 27
Cuando se saquen todos los registros de la pila con la macro RESTORE_ALL (entry.S#L100), el registro %eax se establecerá al valor de retorno (que es lo que espera la biblioteca libc). entry.S [100-111]
100 #define RESTORE_ALL \ 101 popl %ebx; \102 popl %ecx; \103 popl %edx; \ 104 popl %esi; \105 popl %edi; \106 popl %ebp; \107 popl %eax; \ 108 1: popl %ds; \ 109 2: popl %es; \ 110 addl $4,%esp; \111 3: iret;
Lic.Graciela De Luca 28
Recolección de parámetros
En C normalmente se utiliza la pila para pasar parámetros entre funciones.
Antes de realizar la llamada a una función se insertan en la pila todos los parámetros luego se invoca a la función y ésta lee los parámetros de la pila.
Lic.Graciela De Luca 29
Lic.Graciela De Luca 30
En nuestro caso, la macro SAVE_ALL (entry.S#L85) guarda los registros (que es donde se reciben los parámetros de las llamadas) en la pila (push)
Si llamamos a una función C, ésta se comportará como si otra función en C le hubiera pasado los parámetros.
Lic.Graciela De Luca 31
Ejecución de la llamada al sistema
Ej: llamada kill, cuando se ejecute la instrucción
202 call *SYMBOL_NAME(sys_call_table)(,%eax,4)
llama a la función C que se encuentra en la entrada 37 (include/asm-i386/unistd.h#L44) de la tabla sys_call_table [entry.S#L436].
El código de la biblioteca libc se asigno el valor 0x25(37) al registro %eax antes de ejecutar la instrucción int 0x80:
... a: b8 25 00 00 00 mov $0x25,%eax f: cd 80 int $0x80 ...
El tamaño de cada dirección es de 32 bits, o sea 4 bytes.
La función invocada es sys_kill(int pid, int sig) [kernel/signal.c#L978], que se encargará de enviar la señal sig al proceso con pid pid.
Lic.Graciela De Luca 32
sys_kill(int pid, int sig)
978 sys_kill(int pid, int sig) 979 {980 struct siginfo info;981982 info.si_signo = sig;983 info.si_errno = 0; 984 info.si_code = SI_USER;985 info.si_pid = current->pid; 986 info.si_uid = current->uid; 987 988 return kill_something_info(sig, &info, pid); 989 }990
Lic.Graciela De Luca 33
Ejecución de la llamada al sistema
Los parámetros que el usuario le paso a la función kill de la biblioteca libc han pasado por los registros %ebx y %ecx,
Se han copiado en la pila del núcleo y ese valor de la pila, en el lenguaje C, se ve ahora como los parámetro pid y sig de la función sys_kill.
Lic.Graciela De Luca 34
Saliendo del núcleo: ret_from_syscall
Al finalizar la ejecución de la llamada al sistema se ejecuta el código que se encuentra en ret_from_sys_call [entry.S#L204].
Este código lleva a cabo algunas comprobaciones antes de volver a modo usuario.
Lic.Graciela De Luca 35
Se deshabilitan las interrupciones.
Durante la ejecución de la llamada al sistema el proceso ha podido cambiar de estado, y por lo tanto, haberse marcado la necesidad de planificar de nuevo, poniendo su campo need_resched a .T.
Aquí se comprueba si esta variable es .T. y en caso afirmativo saltamos a reschedule, donde se llama al planificador [sched.c#L539] (#L206 [entry.S#L206]). (entry.S [258-260])
258 reschedule: 259 call SYMBOL_NAME(schedule) # test260 jmp ret_from_sys_call
Lic.Graciela De Luca 36
Saliendo del núcleo: ret_from_syscall
Se comprueba si el proceso activo tiene señales pendientes, en cuyo caso se le envían en el código de signal_return [entry.S#L208 ]
Lic.Graciela De Luca 37
213 ALIGN
214 signal_return:
215 sti
216 testl $(VM_MASK),EFLAGS(%esp)
217 movl %esp,%eax
218 jne v86_signal_return
219 xorl %edx,%edx
220 call SYMBOL_NAME(do_signal)
221 jmp restore_all
222
Lic.Graciela De Luca 38
Finalmente se restauran todos los registros con RESTORE_ALL entry.S#L100 (incluido %eax )
Se retorna de la interrupción (int), reponiendo el modo del procesador y la pila a la que tiene acceso el proceso en modo usuario.
Se puede observar que la ejecución más frecuente
de system_call [entry.S#L187] (la llamada es correcta, no está siendo monitorizada, no hay que replanificar y no hay señales pendientes) está optimizada para no tomar absolutamente ningún salto, a excepción de la propia llamada a la función.
Lic.Graciela De Luca 39
Resumen 1. La biblioteca coloca en los registros del procesador
los parámetros de la llamada.
2. Se produce la interrupción software (trap) 0x80. El descriptor de interrupción. 0x80 apunta a la rutina system_call.
3. Se guardan el registro %eax. El resto de los registros con SAVE_ALL.
4. Se verifica que el número de llamada al sistema corresponde con una llamada válida.
5. Se salta a la función que implementa el servicio pedido:call *SYMBOL_NAME(sys_call_table)(,%eax,4)
Lic.Graciela De Luca 40
Resumen
Si mientras se atendía la llamada al sistema se ha producido algún evento que requiera llamar al planificador, se llama en este punto.
Si el proceso al que se va a retornar tiene señales pendientes, se le envían ahora.
Se restauran los valores de los registros con RESTORE_ALL y se vuelve de la interrupción software.
La biblioteca comprueba si la llamada ha producido algún error, y en este caso guarda en la variable errno el valor de retorno.
Lic.Graciela De Luca 41
Lic.Graciela De Luca 42
85 #define SAVE_ALL \ 86 cld; \ 87 pushl %es; \ 88 pushl %ds; \ 89 pushl %eax; \ 90 pushl %ebp; \ 91 pushl %edi; \ 92 pushl %esi; \ 93 pushl %edx; \ 94 pushl %ecx; \ 95 pushl %ebx; \ 96 movl $(__KERNEL_DS),%edx; \ 97 movl %edx,%ds; \ 98 movl %edx,%es; volver
Lic.Graciela De Luca 43
70 /*
71 * these are offsets into the task-struct.
72 */
73 state = 0
74 flags = 4
75 sigpending = 8
76 addr_limit = 12
77 exec_domain = 16
78 need_resched = 20
79 tsk_ptrace = 24
80 processor = 52
VOLVER