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"

Que dice "info idt"

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

Esto se logra con:

TSS: times tss64_struc_size               db  0

La estructura de TSS de 64 bits está disponible mas abajo.

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:
mov     eax,TSS
mov     [TSS_sel+gdt+2],ax
mov     [TSS+4],rsp
mov	eax,TSS_sel
ltr	ax

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