Tabla de Contenidos
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 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"
<bochs:4> info tab cr3: 0x00090000 0x00000000-0x001fffff -> 0x00000000-0x001fffff <bochs:5>
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.
— Marcelo Doallo 2012/07/05 21:03