====== Cambiar de nivel cero a tres en IA-32e ====== ===== Objeto del documento ===== Brindar recomendaciones para el pasaje de nivel de privilegio cero a tres en IA-32e. A partir del ejemplo de programa en IA-32e aportado por el Ing. Dario Alpern. ===== Punto de partida ===== El programa long.asm (disponible haciendo click [[http://www.electron.frba.utn.edu.ar/~mdoallo/descargas/ej3.3-pag_ia32e.tar.gz|aquí]]) propone lo siguiente: \\ ; Hacer un programa que muestre la cantidad de decimas de segundo que estuvo ; corriendo en modo largo (64 bits) y la cantidad de teclas presionadas. ; Utilizar para ello las interrupciones en modo protegido 8 (reloj) y 9 (teclado). ; El cuerpo principal de ejecución se detiene con hlt ; ; Hecho por Dario Alejandro Alpern el 11 de marzo de 2008. ; ==== Que dice "info gdt" ==== * Entrada nula * Segmento de código de 64 bits con DPL=0 (cs_sel_64) * Segmento de código de 32 bits con DPL=0 (cs_sel_32) * Segmento de datos de 32 bits (ds_sel) ==== Que dice "info idt" ==== * Puerta de interrupción en 8 con DPL=0 (cs_sel_64:int8han) * Puerta de interrupción en 9 con DPL=0 (cs_sel_64:int9han) Con esto podemos deducir que el PIC no está siendo reubicado. ==== Que dice "info tab" ==== info tab cr3: 0x00090000 0x00000000-0x001fffff -> 0x00000000-0x001fffff Esto nos dice que tenemos una página de dos MB con **identity mapping** ===== ¿Cual es la idea? ===== Utilizar "int 30h" para bajar el código de nivel cero a tres.\\ La paginación permanece invariable.\\ El timer tick se usa para actualizar pantalla ejecutando código de nivel 0 como antes.\\ Lo mismo para el manejo del teclado.\\ Probar "int 80h" para acceder a nivel cero desde el tres.\\ El programa para detenerse debe utilizar "jmp $" en vez de "halt" (Está claro que esto consume CPU, es sólo porque está en nivel tres).\\ ===== Manos a la obra ===== * En la GDT declaramos tres segmentos nuevos. Uno para código de 64 bits con DPL=3, otro de datos de 32 bits también con DPL=3 y otro para TSS (Task State Segment) también de 64 bits con DPL=0. * En la IDT agregamos una puerta de interrupción en 30h con DPL=0, que será para hacer el cambio de privilegio (de cero a tres). También agregamos otra puerta de interrupción en 80h, esta será para acceso a servicios del kernel por código que corre en nivel tres. * Dado que describimos una TSS en la GDT debemos reservar espacio en memoria a tal efecto. Esto se logra con: TSS: times tss64_struc_size db 0 La estructura de TSS de 64 bits está disponible mas abajo. * Asegurarse que la página esté accesible a nivel USER. * Definir pila de nivel cero (porque no me gusta como está en long.asm) mov rsp,pila_0 mov ax,ds_sel mov ss,ax Donde pila_0 de define como:\\ align 256 times 256 db 0 pila_0: * Definir pila de nivel tres. * Inicializar la base del descriptor de TSS en la GDT mov eax,TSS mov [TSS_sel+gdt+2],ax * Guardar rsp de nivel 0 en la TSS mov [TSS+4],rsp * Cargar TSS en TR mov eax,TSS_sel ltr ax * Invocar INT 30h para pasar de nivel cero a tres * Luego de esto se debe verificar que estamos en nivel 3. * Hacer pruebas de manejo de pila de nivel 3 y uso de int 80h. * Finalmente "colgar" la ejecución con un jmp $. ==== La magia está en int 30h ==== Al ejecutar la interrupción se guarda en la pila de nivel 0 lo siguiente: RIP, CS, RFLAGS, RSP y SS. \\ La idea es alterar CS, RSP y SS de la pila. Para que luego al hacer IRETQ se cambie de nivel.\\ push rbp mov rbp,rsp push rax ; para trabajar mov rax,cs_sel3_64 mov [rbp+16],rax mov rax,pila_3 mov [rbp+32],rax mov rax,ds_sel3 mov [rbp+40],rax pop rax pop rbp iretq ==== Estructura de TS de 64 bits ==== struc tss64_struc resd 1 ; Reservada .reg_RSP0 resq 1 .reg_RSP1 resq 1 .reg_RSP2 resq 1 resq 1 ; Reservada .reg_IST1 resq 1 .reg_IST2 resq 1 .reg_IST3 resq 1 .reg_IST4 resq 1 .reg_IST5 resq 1 .reg_IST6 resq 1 .reg_IST7 resq 1 resd 1 ; Reservada resd 1 ; Reservada resw 1 ; Reservada .reg_IOMAP resw 1 endstruc ==== Si todo sale bien ... ==== El programa debe lucir igual que el original (long.asm), sólo que al hacer break el código debe estar en el "jmp $" de nivel 3, a menos que tengamos la suerte de detenerlo justo en alguno de los handler de interrupción (8 o 9) donde estaría corriendo en anillo 0. ===== Agradecimientos ===== A Dario Alpern por el aporte de long.asm. A Alejandro Furfaro por meternos en este baile. A Mariano Gonzalez y Juan Carlos Cuttitta que colaboran con ideas todo el tiempo. Al cuerpo docente de la cátedra de TDIII.\\ Se aceptan críticas y comentarios.\\ --- //[[mdoallo@electron.frba.utn.edu.ar|Marcelo Doallo]] 2012/07/05 21:03//