2012-02-04 18 views
10

Actualmente estoy jugando con x86 Assember para agudizar mis habilidades de programación de bajo nivel. Actualmente, estoy enfrentando un pequeño problema con el esquema de direccionamiento en modo protegido de 32 bits.Assembler salta en Modo protegido con GDT

La situación es la siguiente:

Tengo un programa cargado en 0x7e0 que cambia la CPU para el modo protegido y salta a la etiqueta de acuerdo en el código:

[...] 
code to switch CPU in Protected Mode 
[...] 

jmp ProtectedMode 


[...] 

bits 32 

ProtectedMode: 
    .halt: 
     hlt 
     jmp .halt 

Esto funciona absolutamente bien por lo lejos. El "JMP ProtectedMode" funciona sin un salto lejano explícito para borrar la cola de captación previa, ya que este programa está cargado con el desplazamiento 0 (org 0 al comienzo), lo que hace que el segmento de código apunte a la ubicación correcta.

Mi problema actual ahora es que dentro de la etiqueta "ProtectedMode" quiero saltar a otro programa que se carga en 0x8000 (lo comprobé con un volcado de memoria, la función de carga funcionó correctamente y el programa está cargado correctamente a 0x8000).

Dado que la CPU ahora está en Modo Protegido y no en RealMode, el esquema de direccionamiento es diferente. ProtectedMode utiliza selectores de descriptores para buscar una dirección base y un límite en una tabla de descriptores para agregar el desplazamiento dado y recuperar la dirección física (según entendí). Por lo tanto, fue necesario instalar un GDT antes de ingresar a ProtectedMode.

mina está buscando como el siguiente:

%ifndef __GDT_INC_INCLUDED__ 
%define __GDT_INC_INCLUDED__ 

;********************************* 
;* Global Descriptor Table (GDT) * 
;********************************* 
NULL_DESC: 
    dd 0   ; null descriptor 
    dd 0 

CODE_DESC: 
    dw 0xFFFF  ; limit low 
    dw 0   ; base low 
    db 0   ; base middle 
    db 10011010b ; access 
    db 11001111b ; granularity 
    db 0   ; base high 

DATA_DESC: 
    dw 0xFFFF  ; data descriptor 
    dw 0   ; limit low 
    db 0   ; base low 
    db 10010010b ; access 
    db 11001111b ; granularity 
    db 0   ; base high 

gdtr: 
    Limit dw 24   ; length of GDT 
    Base dd NULL_DESC ; base of GDT 

%endif ;__GDT_INC_INCLUDED__ 

y se carga a la GDT registrarse a través

lgdt [gdtr] 

Lo que no entiendo hasta ahora es, ¿cómo puedo Ahora salta a la física dirección 0x8000 en ProtectedMode usando el GDT?

Mis primeros pensamientos fueron seleccionar el Descriptor de Código (CODE_DESC) que debería apuntar a 0x7e00 (se cargó el programa actual) y utilizar el desplazamiento necesario para obtener 0x8000 (512 bytes), lo que da como resultado la instrucción de salto :

jmp CODE_DESC:0x200 

Pero esto no funciona.

jmp 0x7e0:0x200 

no funciona bien ...

¿Tiene alguna idea de lo que me falta aquí? Tal vez no entendí algo esencial dentro del esquema de direccionamiento de 32-Bit ProtectedMode y el uso del GDT.

[EDIT] Código completo:

bits 16 
org 0      ; loaded with offset 0000 (phys addr: 0x7e00) 

jmp Start 

Start: 
    xor ax, ax 
    mov ax, cs 
    mov ds, ax    ; update data segment 

    cli      ; clear interrupts 

    lgdt [gdtr]    ; load GDT from GDTR (see gdt_32.inc) 

    call OpenA20Gate  ; open the A20 gate 

    call EnablePMode  ; jumps to ProtectedMode 

;****************** 
;* Opens A20 Gate * 
;****************** 
OpenA20Gate: 
    in al, 0x93   ; switch A20 gate via fast A20 port 92 

    or al, 2   ; set A20 Gate bit 1 
    and al, ~1   ; clear INIT_NOW bit 
    out 0x92, al 

    ret 

;************************** 
;* Enables Protected Mode * 
;************************** 
EnablePMode: 
    mov eax, cr0 
    or eax, 1 
    mov cr0, eax 

    jmp ProtectedMode ; this works (jumps to label and halts) 
    ;jmp (CODE_DESC-NULL_DESC):ProtectedMode ; => does not work 
    ;jmp 08h:ProtectedMode , => does not work 

;*************** 
;* data fields * 
;* &includes * 
;*************** 
%include "gdt_32.inc" 

;****************** 
;* Protected Mode * 
;****************** 
bits 32 

ProtectedMode: 
    ;here I want to jump to physical addr 0x8000 (elf64 asm program) 

    .halt: 
     hlt 
     jmp .halt 

Respuesta

11

hay varios problemas en el código.

primer lugar, su GDTR.Base contiene el desplazamiento de la GDT desde el principio del código ya que su código se compila para comenzar en la dirección 0 (debido a org 0). La dirección base debe ser la dirección física, no una dirección relativa. IOW, si mantiene este org 0, debe agregar CS * 16 (= 0x7e00) al Base.

En segundo lugar, debido a que la misma org 0, los desplazamientos de 32 bits en el código (después de bits 32 y ProtectedMode:) no son iguales a las direcciones físicas que se corresponden con, son 0x7e00 menos de las direcciones físicas. OTOH, los segmentos definidos en su GDT comienzan en la dirección física 0 (porque las porciones base de las entradas GDT son 0) y no en 0x7e00. Esto significa que cuando intente utilizar estos segmentos con su código/datos, perderá las direcciones por 0x7e00. Si desea conservar org 0, las direcciones base en el GDT deben configurarse en 0x7e00.

O puede cambiar org 0 a org 0x7e00 y luego las bases en el GDT deben ser 0. Y no tendrá que ajustar GDTR.Base por 0x7e00, 0 hará.

esto debería funcionar:

bits 16 
org 0x7e00     ; loaded at phys addr 0x7e00 
          ; control must be transferred with jmp 0:0x7e00 

    xor ax, ax 
    mov ds, ax    ; update data segment 

    cli      ; clear interrupts 

    lgdt [gdtr]    ; load GDT from GDTR (see gdt_32.inc) 

    call OpenA20Gate  ; open the A20 gate 

    call EnablePMode  ; jumps to ProtectedMode 

;****************** 
;* Opens A20 Gate * 
;****************** 
OpenA20Gate: 
    in al, 0x93   ; switch A20 gate via fast A20 port 92 

    or al, 2   ; set A20 Gate bit 1 
    and al, ~1   ; clear INIT_NOW bit 
    out 0x92, al 

    ret 

;************************** 
;* Enables Protected Mode * 
;************************** 
EnablePMode: 
    mov eax, cr0 
    or eax, 1 
    mov cr0, eax 

    jmp (CODE_DESC - NULL_DESC) : ProtectedMode 

;*************** 
;* data fields * 
;* &includes * 
;*************** 
;%include "gdt_32.inc" 
;********************************* 
;* Global Descriptor Table (GDT) * 
;********************************* 
NULL_DESC: 
    dd 0   ; null descriptor 
    dd 0 

CODE_DESC: 
    dw 0xFFFF  ; limit low 
    dw 0   ; base low 
    db 0   ; base middle 
    db 10011010b ; access 
    db 11001111b ; granularity 
    db 0   ; base high 

DATA_DESC: 
    dw 0xFFFF  ; limit low 
    dw 0   ; base low 
    db 0   ; base middle 
    db 10010010b ; access 
    db 11001111b ; granularity 
    db 0   ; base high 

gdtr: 
    Limit dw gdtr - NULL_DESC - 1 ; length of GDT 
    Base dd NULL_DESC ; base of GDT 

;****************** 
;* Protected Mode * 
;****************** 
bits 32 

ProtectedMode: 
    mov  ax, DATA_DESC - NULL_DESC 
    mov  ds, ax ; update data segment 

    .halt: 
     hlt 
     jmp .halt 

Tenga en cuenta que un límite de segmento es igual al tamaño de los segmentos menos 1.

algunos puntos más ... Cargar todos los registros de segmento con selectores válidos o 0. Además, configurar la pila Si tiene basura allí (o valores antiguos del modo real), cuando comience a jugar con interrupciones/excepciones, tendrá más bloqueos.

Finalmente, no sé qué es elf64, pero tendrá que encargarse del asunto org para otros módulos y asegurarse de que todas las direcciones generadas correspondan a las direcciones de carga. Y si tiene la intención de habilitar el modo de 64 bits, hay mucho trabajo por hacer. Le aconsejo que no se apresure al modo de 64 bits ya que está tropezando con cosas relativamente simples.

+0

Gracias por la explicación ... Esta es exactamente la razón por la que estoy haciendo esto, y no es tan simple cuando se hace esto desde cero por primera vez simplemente leyendo referencias x86 :)! Por cierto: ¿hay algún gran libro que pueda aconsejar que maneje exactamente este tipo de temas? –

+1

No sé buenos libros. La documentación oficial de Intel y AMD tiene toda la información, simplemente no es un tipo típico de libro o libro de texto que leería fácilmente y comprendería todo de inmediato (por cierto, hay muchos errores ortográficos y errores ocasionales en los documentos de Intel). Hay muchos artículos y tutoriales en línea. Y siempre puedes experimentar O vea el código de alguien y haga preguntas. Vea estos grupos: [alt.os.development] (http://groups.google.com/group/alt.os.development/topics), [comp.lang.asm.x86] (http://groups.google .com/group/comp.lang.asm.x86/topics). –

+0

¡Gracias por tu consejo! Echaré un vistazo a eso! –

3

Un par de cosas. En primer lugar, su código actual no entra técnicamente en modo protegido. Ingrese al modo protegido cargando cs con un descriptor del GDT. Como no puede establecer directamente el registro cs, la forma más fácil de hacerlo es utilizando un salto lejano. Vuelva a colocar el salto de corriente con:

jmp (CODE_DESC-NULL_DESC):ProtectedMode 

En segundo lugar, la base para su segmento de código es 0, no 0x7e00.Si miras los cuatro bytes etiquetados con la palabra "base", todos son 0. Tienes dos opciones. Cambie su GDT para tener una base de 0x7e00, o agregue directivas para cambiar la dirección de carga para todos los códigos de modo protegido para una base de 0.

Una vez que haya hecho ambas cosas, puede ir a su programa usando una instrucción de salto normal. Si decide dejar su GDT como es, se utilizaría la dirección completa:

jmp 0x8000 

Si decide cambiar la base de su segmento de código, tendrá que utilizar la dirección relativa a eso.

jmp 0x200 

More information about the GDT
More information about entering protected mode

+0

Gracias por su respuesta. OK: cuando se usa la instrucción de salto "jmp CODE_DESC: Modoprotegido", la CPU triplica las fallas y restablece (ya que esta dirección de salto parece saltar a alguna parte). "jmp ProtectedMode" salta a la etiqueta correcta y detiene el sistema. Dado que esto podría estar relacionado con el problema de la base GDT, cambiaré el GDT e intentaré de nuevo. Gracias por su rápida respuesta !! –

+0

@ughoavgfhw ¿Quiere decir 'jmp (CODE_DESC-NULL_DESC): ProtectedMode'? – Nayuki

+0

@NayukiMinase Gracias por captar eso, supuse que ya eran compensaciones. – ughoavgfhw

Cuestiones relacionadas