Pregunta

Estoy intentando hackear los primeros bits de un kernel. Actualmente tengo todo el kernel compilado como código C, y he logrado que muestre el texto en la ventana de la consola y toda esa bondad. Ahora, quiero comenzar a aceptar entradas de teclado para poder hacer un uso de la cosa y comenzar con la gestión de procesos.

Estoy usando DJGPP para compilar y cargar con GRUB. También estoy usando una pequeña cantidad de ensamblaje que básicamente salta directamente a mi código C compilado y estoy feliz desde allí.

Toda la investigación que he hecho parece apuntar a un ISR a $ 0x16 para leer el siguiente carácter del búfer del teclado. Por lo que puedo decir, se supone que esto almacena el valor ASCII en ah, y el código de clave en al, o algo por el estilo. Estoy intentando codificar esto usando la siguiente rutina en el ensamblaje en línea:

char getc(void) 
{
    int output = 0;

    //CRAZY VOODOO CODE
    asm("xor %%ah, %%ah\n\t"
        "int <*>x16"
        : "=a" (output)
        : "a" (output)
        : 

        );

    return (char)output;
}

Cuando se llama a este código, el núcleo se bloquea de inmediato. (Lo estoy ejecutando en VirtualBox, no sentí la necesidad de probar algo tan básico en hardware real).

Ahora tengo un par de preguntas. Nadie ha podido decirme si (desde que mi código fue lanzado desde GRUB) estoy ejecutando en modo real o modo protegido en este momento. No he dado el salto de una manera u otra, estaba planeando correr en modo real hasta que configuré un controlador de procesos.

Entonces, suponiendo que estoy ejecutando en modo real, ¿qué estoy haciendo mal y cómo lo arreglo? Solo necesito una rutina básica de getc, preferiblemente no bloqueante, pero me darán una paliza si Google está ayudando en esto. Una vez que pueda hacer eso, puedo hacer el resto desde allí.

Supongo que lo que estoy preguntando aquí es, ¿estoy cerca del camino correcto? ¿Cómo se hace generalmente una entrada de teclado en este nivel?

EDITAR: OOhh ... entonces estoy corriendo en modo protegido. Esto explica el problema al intentar acceder a las funciones en modo real.

Entonces supongo que estoy buscando la forma de acceder al IO del teclado desde el modo protegido. Es posible que pueda encontrarlo por mi cuenta, pero si alguien se entera, siéntete libre. Gracias de nuevo.

¿Fue útil?

Solución

Si estás compilando con gcc, a menos que estés usando el loco " .code16gcc " Engaña a los usos del kernel de Linux (lo cual dudo mucho), no puedes estar en modo real. Si está utilizando la especificación de arranque múltiple de GRUB, GRUB mismo está cambiando al modo protegido para usted. Entonces, como han señalado otros, tendrá que hablar directamente con el controlador de teclado / mouse compatible con 8042. A menos que se trate de un teclado / mouse USB y la emulación 8042 esté deshabilitada, en la que necesitaría una pila USB (pero puede usar el protocolo de arranque para el teclado / mouse, que es más sencillo).

Nadie dijo que escribir un kernel del sistema operativo era sencillo.

Otros consejos

El código que tienes allí está intentando acceder a un servicio de BIOS en modo real. Si está ejecutando en modo protegido, lo que probablemente está considerando que está escribiendo un kernel, entonces la interrupción no funcionará. Deberá realizar una de las siguientes acciones:

  • Coloque la CPU en modo real, asegurándose de que la tabla de vectores de interrupción sea correcta y use el código de modo real que tiene o
  • Escriba su propio controlador de teclado en modo protegido (es decir, utilice las instrucciones de entrada / salida).

La primera solución incluirá una sobrecarga de rendimiento en el tiempo de ejecución, mientras que la segunda requerirá información sobre el IO del teclado.

Tengo un pedazo de GeekOS que parece hacer

In_Byte(KB_CMD);

y luego

In_Byte(KB_DATA);

para buscar un código de escena. Lo puse: keyboard.c y keyboard.h . KB_CMD y KB_DATA son 0x64 y 0x60 respectivamente. Quizás también podría señalar que esto se hace en un controlador de interrupción para intr: 1.

Estás haciendo lo correcto, pero me parece recordar que djgpp solo genera salidas en modo protegido, de las que no puedes llamar interrupciones. ¿Puede pasar al modo real como otros han sugerido, o prefiere dirigirse directamente al hardware?

A los fines de la explicación, supongamos que usted estaba escribiendo todo en lenguaje ensamblador, en el cargador de arranque y en el kernel (* tos *, he hecho esto).

En el modo real, puede hacer uso de las rutinas de interrupción que provienen de la BIOS. También puedes reemplazar los vectores de interrupción con los tuyos. Sin embargo, todo el código es un código de 16 bits, que es no compatible con binarios con un código de 32 bits.

Cuando salta a través de unos cuantos aros para llegar al modo protegido (incluida la reprogramación del controlador de interrupción, para evitar el hecho de que IBM usó interrupciones reservadas por Intel en la PC), tiene la oportunidad de configurar 16- y Segmentos de código de 32 bits. Esto se puede utilizar para ejecutar código de 16 bits. ¡Así que puedes usar esto para acceder a la interrupción de getchar!

... no del todo. Para que esta interrupción funcione, realmente necesita datos en un búfer de teclado que fue colocado allí por un ISR diferente, el que se activa con el teclado cuando se presiona una tecla. Existen varios problemas que prácticamente le impiden utilizar los ISR de BIOS como ISR de hardware reales en modo protegido. Por lo tanto, las rutinas de teclado de la BIOS son inútiles.

Las videollamadas de BIOS, por otro lado, están bien, porque no hay ningún componente activado por hardware. Tienes que preparar un segmento de código de 16 bits, pero si eso está bajo control, puedes cambiar los modos de video y ese tipo de cosas utilizando interrupciones de BIOS.

Volver al teclado: lo que necesita (nuevamente, suponiendo que ESTÁ escribiendo todo el código) es escribir un controlador de teclado. A menos que seas un masoquista (yo soy uno), entonces no vayas allí.

Una sugerencia: intente escribir un kernel multitarea en modo Real. (Eso es el modo de 16 bits.) ¡Puedes usar todas las interrupciones del BIOS! No obtiene protección de memoria, pero aún puede obtener la multitarea preventiva al enganchar la interrupción del temporizador.

Solo una idea: mirando a GRUB para DOS fuente (asm.s), la < La función code> console_checkkey está utilizando la BIOS INT 16H Function 01 , y no la función 00, como está intentando hacer. Quizás desee comprobar si una clave está esperando para ser ingresada.

El código console_checkkey está configurando la CPU en modo real para usar el BIOS, como @ skizz sugirió .

También puedes probar a usar las funciones de GRUB directamente (si aún están asignadas en modo real).

Una nota sobre la lectura del origen del ensamblaje: en esta versión

movb    
/*
 * int console_checkkey (void)
 *  if there is a character pending, return it; otherwise return -1
 * BIOS call "INT 16H Function 01H" to check whether a character is pending
 *  Call with   %ah = 0x1
 *  Return:
 *      If key waiting to be input:
 *          %ah = keyboard scan code
 *          %al = ASCII character
 *          Zero flag = clear
 *      else
 *          Zero flag = set
 */
 ENTRY(console_checkkey)
  push  %ebp
  xorl  %edx, %edx

  call  EXT_C(prot_to_real) /* enter real mode */

  .code16

  sti       /* checkkey needs interrupt on */

  movb  <*>x1, %ah
  int   <*>x16

  DATA32    jz  notpending

  movw  %ax, %dx
  //call    translate_keycode
  call  remap_ascii_char
  DATA32    jmp pending

notpending:
  movl  <*>xFFFFFFFF, %edx

pending:
  DATA32    call    EXT_C(real_to_prot)
  .code32

  mov   %edx, %eax

  pop   %ebp
  ret
x1, %ah

significa mover byte constante (0x1) para registrar %ah

El console_checkkey de GRUB asm.s:

<*>

Ejemplo para sondear el controlador del teclado:

Start:
      cli
      mov al,2        ; dissable IRQ 1
      out 21h,al
      sti

;--------------------------------------
; Main-Routine
AGAIN:
      in al,64h       ; get the status
      test al,1       ; check output buffer
      jz short NOKEY
      test al,20h     ; check if it is a PS2Mouse-byte
      jnz short NOKEY
      in al,60h       ; get the key

; insert your code here (maybe for converting into ASCII...)

NOKEY:
      jmp AGAIN
;--------------------------------------
; At the end
      cli
      xor al,al       ; enable IRQ 1
      out 21h,al
      sti
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top