assembly operating-system x86 bootloader protected-mode

assembly - gestor de arranque-conmutando el procesador al modo protegido



operating-system x86 (2)

  1. Algunas implementaciones de BIOS pasan al modo protegido antes de ingresar al gestor de arranque. La mayoría no. Es posible que el BIOS cambie al modo protegido durante un breve período y vuelva a conectarse antes de ir al gestor de arranque, lo que le permitiría utilizar algunos de los beneficios del modo protegido (como 32 bits es el tamaño predeterminado de la dirección). La razón por la que el gestor de arranque debería estar en modo real es que la mayoría de las funciones del BIOS solo funcionan en modo real, por lo que debe estar en modo real para usarlas.

  2. ljmp especifica un segmento de código para cambiar además de la dirección a la que saltar. Son tan similares que (al menos en GAS) el ensamblador cambiará un jmp con 2 operandos a un ljmp por usted.

  3. ljmp es una de las únicas formas de cambiar el registro cs. Esto debe hacerse para activar el modo protegido, ya que el registro cs debe contener el selector para un segmento de código en el GDT. (En caso de que quiera saber, las otras formas de cambiar cs son llamadas lejanas, retorno lejano e interrupción de retorno)

  4. Vea el ítem 1. O el BIOS volvió al modo real, o este gestor de arranque no funcionará con este BIOS.

  5. Consulte el elemento 3. Cambia cs para especificar un segmento de código de 32 bits, por lo que el procesador pasa al modo de 32 bits.

  6. Cuando miró el archivo .asm, la instrucción se interpretó como si el tamaño de la dirección fuera de 32 bits, pero GDB lo interpretó como si el tamaño de la dirección fuera de 16 bits. Los datos en la dirección de la instrucción serían 0xEA 32 7C 08 00 66 B8. EA es el código de operación de salto largo. En un espacio de direcciones de 32 bits, la dirección se especificará utilizando los siguientes cuatro bytes, para una dirección de 0x87C32, pero en un espacio de direcciones de 16 bits, solo se utilizan 2 bytes, para una dirección de 0x7C32. Los 2 bytes posteriores a la dirección especifican el segmento de código solicitado, que sería 0xB866 en el modo de 32 bits y 0x0008 en el modo de 16 bits. El 0x66 B8 es el comienzo de la siguiente instrucción, que está moviendo un valor inmediato de 16 bits en el registro de hacha, probablemente para configurar los segmentos de datos para el modo protegido.

Tengo dificultades para entender cómo funciona un gestor de arranque simple. El gestor de arranque del que estoy hablando es el del curso de MIT "Ingeniería de sistemas operativos".

Primero, permítame mostrarle un fragmento del código de ensamblaje que ejecuta el BIOS:

[f000:fec3] 0xffec3: lidtw %cs:0x7908 [f000:fec9] 0xffec9: lgdtw %cs:0x7948 [f000:fecf] 0xffecf: mov %cr0,%eax [f000:fed2] 0xffed2: or $0x1,%eax [f000:fed6] 0xffed6: mov %eax,%cr0 [f000:fed9] 0xffed9: ljmpl $0x8,$0xffee1

Por lo que parece, este código configura la tabla de interrupción y la tabla de descriptores y luego activa el modo protegido.

  1. ¿Por qué entramos en modo protegido en el BIOS? ¿No debería ejecutarse el gestor de arranque en modo real (por cierto, ¿por qué necesita ejecutarse en modo real?)
  2. Busqué pero no encontré en ninguna parte exactamente cómo funciona la instrucción ljmpl, y es la diferencia entre él y ljmp y jmp regular. Agradecería que alguien apuntara en la dirección correcta.
  3. ¿Por qué realizamos el salto? ¿Cuál es el propósito de esta instrucción?

Pasando al código del cargador de arranque -

# Switch from real to protected mode, using a bootstrap GDT # and segment translation that makes virtual addresses # identical to their physical addresses, so that the # effective memory map does not change during the switch. lgdt gdtdesc movl %cr0, %eax orl $CR0_PE_ON, %eax movl %eax, %cr0 # Jump to next instruction, but in 32-bit code segment. # Switches processor into 32-bit mode. ljmp $PROT_MODE_CSEG, $protcseg

  1. Dice que el procesador está en modo real, pero acabamos de ver que el BIOS cambia al modo protegido ... Estoy confundido, ¿cómo puede ser posible?
  2. ¿Cómo cambiamos al modo de 32 bits? ¿Qué hace que el procesador pase mágicamente al modo de 32 bits debido a la instrucción ljmp?

Y otra cosa que no entiendo: cuando sigo la ejecución del gestor de arranque con gdb veo que se ejecutan las siguientes instrucciones (esa es la instrucción ljmp del código del gestor de arranque):

ljmp $0x8,$0x7c32

Pero cuando miré en el archivo .asm, vi lo siguiente:

ljmp $0xb866,$0x87c32

Totalmente perdido aquí: ¿cómo es que las instrucciones escritas en el archivo .asm y las instrucciones ejecutadas son diferentes? Tengo la corazonada de que esto tiene que ver con el modo protegido y la forma en que traduce las direcciones, pero realmente no lo entiendo.

¡Apreciaría cualquier ayuda!


¿Por qué entramos en modo protegido en el BIOS? ¿No debería ejecutarse el gestor de arranque en modo real (por cierto, ¿por qué necesita ejecutarse en modo real?)

El modo protegido simplemente ofrece mucha más característica que el modo real: esencialmente el mecanismo de privilegio de anillo de protección de la CPU Intel (http://en.wikipedia.org/wiki/Ring_(computer_security), la ejecución en modo de 32 bits, etc.

Busqué pero no encontré en ninguna parte exactamente cómo funciona la instrucción ljmpl, y es la diferencia entre él y ljmp y jmp regular. Agradecería que alguien apuntara en la dirección correcta.

ljmpl y ljmp es el mismo contextualmente aquí.

¿Por qué realizamos el salto? ¿Cuál es el propósito de esta instrucción?

Esto es obligatorio según lo documentado en el manual de Intel, y documentado en línea en el código que se muestra a continuación también.

Para la transición de real a protegida, se implementa en el cargador de arranque stage2 aquí:

http://src.illumos.org/source/xref/illumos-gate/usr/src/grub/grub-0.97/stage2/asm.S#real_to_prot

974 /* load the GDT register */ 975 DATA32 ADDR32 lgdt gdtdesc 976 977 /* turn on protected mode */ 978 movl %cr0, %eax 979 orl $CR0_PE_ON, %eax 980 movl %eax, %cr0 981 982 /* jump to relocation, flush prefetch queue, and reload %cs */ 983 DATA32 ljmp $PROT_MODE_CSEG, $protcseg 984

Como puede ver, cada parte del código tiene una función, y ljmp es esencialmente para eliminar la cola de captación previa, como se requiere en el manual de Intel, no recuerdo dónde.