Pergunta

Eu estou no processo de tentar cortar juntos os primeiros bits de um kernel. Atualmente tenho todo o kernel compilado para baixo como o código C, e eu consegui fazê-lo exibir texto na janela do console e tudo isso bem bondade. Agora, eu quero começar a aceitar a entrada do teclado para que eu possa realmente fazer algum uso da coisa e ir em frente na gestão de processos.

Eu estou usando DJGPP para compilar e carregamento com o GRUB. Eu também estou usando um pequeno pedaço de montagem que basicamente vai diretamente em meu código C compilado e estou feliz de lá.

Toda a pesquisa que fiz parece apontar para um ISR em US $ 0x16 para ler no próximo caractere do buffer de teclado. Do que eu posso dizer, isso é suposto para armazenar o valor ASCII em ah, eo código de acesso em al, ou algo nesse sentido. Eu estou tentando código isso usando a seguinte rotina na linha de montagem:

char getc(void) 
{
    int output = 0;

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

        );

    return (char)output;
}

Quando este código é chamado, o núcleo deixa de funcionar imediatamente. (Estou executando-o em VirtualBox, eu não senti a necessidade de tentar algo tão básicas sobre hardware real.)

Agora eu tenho realmente um par de perguntas. Ninguém foi capaz de me dizer se (desde o meu código foi lançado do GRUB) Estou correndo em modo real ou modo protegido no momento. Eu não fiz o salto de uma maneira ou de outra, eu estava pensando em correr em modo real até que eu tenho um manipulador processo de configuração.

Assim, supondo que eu estou correndo em modo real, o que estou fazendo de errado, e como faço para corrigir isso? Eu só preciso de uma rotina getc básica, de preferência sem bloqueio, mas eu vou ser amaldiçoado se google está ajudando em um presente em tudo. Uma vez que eu posso fazer isso, eu posso fazer o resto de lá.

Eu acho que o que eu estou pedindo aqui é, eu estou em qualquer lugar perto o caminho certo? Como é que uma pessoa geralmente ir sobre a obtenção de entrada de teclado a este nível?

EDIT: Oohh ... então eu estou correndo em modo protegido. Isso certamente explica o acidente tentando funções de acesso de modo real depois.

Então eu acho que eu estou procurando como acessar o teclado IO de modo protegido. Eu poderia ser capaz de encontrar isso no meu próprio, mas se alguém acontece a conhecer sensação livre. Obrigado mais uma vez.

Foi útil?

Solução

Se você está compilando com gcc, a menos que você estiver usando o ".code16gcc" louco enganar os usos do kernel do Linux (o que eu duvido muito), você não pode estar em modo real. Se você estiver usando a especificação multiboot GRUB, o GRUB em si é a mudança para o modo protegido para você. Assim, como outros apontaram, você vai ter que falar diretamente com o controlador de teclado 8042-compatível / mouse. A menos que seja um teclado / rato USB e 8042 emulação está desativado, onde você precisaria de uma pilha USB (mas você pode usar o protocolo de "boot" para o teclado / mouse, que é mais simples).

Ninguém disse que escrever um kernel do sistema operacional era simples.

Outras dicas

O código que você tem aí está tentando acessar um serviço de BIOS de modo real. Se você estiver executando em modo protegido, que é provável, considerando que você está escrevendo um kernel, em seguida, a interrupção não vai funcionar. Você vai precisar fazer uma das seguintes opções:

  • Thunk a CPU em modo real, certificando-se a tabela vetor de interrupção está correto e usar o código de modo real que você tem ou
  • Escreva seu próprio manipulador protegido modo teclado (ou seja, utilizar as instruções / out).

A primeira solução vai envolver uma sobrecarga de desempenho de tempo de execução whist o segundo vai exigir algumas informações sobre o teclado IO.

Eu tenho um pedaço de GeekOS que parece fazer

In_Byte(KB_CMD);

e

In_Byte(KB_DATA);

para buscar uma scancode. Eu colocá-lo: keyboard.c e keyboard.h . KB_CMD e KB_DATA sendo 0x64 e 0x60 respectivamente. Eu poderia talvez também de salientar que isso é feito em um manipulador de interrupção para intr:. 1

Você está fazendo a coisa certa, mas eu me lembro que djgpp Saída em modo só gera protegida, o que você não pode chamar interrupções de. você pode cair para o modo real, como já foi sugerido, ou você prefere para abordar o hardware diretamente?

Para efeitos de explicação, vamos supor que você estava escrevendo tudo em linguagem assembly mesmo, carregador de boot e kernel (* tosse * Eu fiz isso).

No modo real, você pode fazer uso das rotinas de interrupção que vêm do BIOS. Você também pode substituir os vetores de interrupção com o seu próprio. No entanto todo o código é um código de 16 bits, que é não binário compatível com código de 32 bits.

Quando você saltar através de algumas aros de queima para chegar ao modo protegido (incluindo a reprogramação do controlador de interrupção, para contornar o fato de que a IBM usou interrupções Intel reservados no PC), você tem a oportunidade de criar 16 e segmentos de código de 32 bits. Isso pode ser usado para executar código de 16 bits. Então você pode usar isso para acessar a interrupção getchar!

... não completamente. Para esta interrupção ao trabalho, você realmente precisa de dados em um buffer de teclado que foi colocado ali por um ISR diferente - o que é acionado pelo teclado quando uma tecla é pressionada. Há várias questões que praticamente impedem usando BIOS ISRs como ISRs de hardware real em modo protegido. Assim, as rotinas de teclado BIOS são inúteis.

chamadas de vídeo BIOS, por outro lado, são muito bem, porque não há nenhum componente acionado por hardware. Você tem que preparar um segmento de código de 16 bits, mas se que está sob controle, então você pode alternar entre os modos de vídeo e esse tipo de coisa usando interrupções de BIOS.

Voltar para o teclado: o que você precisa (novamente assumindo que você está escrevendo todo o código) é escrever um driver de teclado. A menos que você é um masoquista (eu sou um), então não vá lá.

Uma sugestão: tentar escrever um kernel multitarefa no modo Real. (Isso é modo de 16 bits.) Você pode usar todas as interrupções do BIOS! Você não ganha proteção de memória, mas você ainda pode obter multitarefa preemptiva ligando a interrupção timer.

Apenas uma idéia: olhando para GRUB para fonte DOS (asm.s), o console_checkkey função está usando BIOS INT 16H Function 01, e não funcionar 00, como você está tentando fazer. Talvez você gostaria de verificar se uma chave está esperando para ser de entrada.

O código console_checkkey está definindo o CPU para modo real, a fim de usar a BIOS, como @ Skizz sugeriu .

Você também pode tentar usar funções do GRUB directamente (se ainda mapeada em modo real).

Uma nota sobre a leitura fonte de montagem: nesta versão

movb    $0x1, %ah

meios mover byte constante (0x1) para registar %ah

O console_checkkey do GRUB asm.s:

/*
 * 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  $0x1, %ah
  int   $0x16

  DATA32    jz  notpending

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

notpending:
  movl  $0xFFFFFFFF, %edx

pending:
  DATA32    call    EXT_C(real_to_prot)
  .code32

  mov   %edx, %eax

  pop   %ebp
  ret

Exemplo para interrogar o controlador de 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top