Как получить ввод с клавиатуры в сборке x86 bare metal? - PullRequest
4 голосов
/ 20 октября 2008

Я пытаюсь собрать воедино первые кусочки ядра. В настоящее время у меня есть все ядро, скомпилированное как код C, и мне удалось отобразить текст в окне консоли и все такое хорошее. Теперь я хочу начать принимать ввод с клавиатуры, чтобы реально использовать эту вещь и приступить к управлению процессами.

Я использую DJGPP для компиляции и загрузки с GRUB. Я также использую небольшую сборку, которая в основном переходит непосредственно в мой скомпилированный код C, и я счастлив оттуда.

Кажется, что все исследования, которые я провел, указывают на ISR в $ 0x16 для чтения следующего символа из буфера клавиатуры. Из того, что я могу сказать, это должно хранить значение ASCII в ах, и код ключа в al, или что-то в этом роде. Я пытаюсь закодировать это с помощью следующей процедуры встроенной сборки:

char getc(void) 
{
    int output = 0;

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

        );

    return (char)output;
}

Когда вызывается этот код, ядро ​​сразу падает. (Я запускаю его на VirtualBox, я не чувствовал необходимости пробовать что-то базовое на реальном оборудовании.)

Теперь у меня есть пара вопросов. Никто не смог сказать мне, если (так как мой код был запущен из GRUB), я работаю в реальном режиме или в защищенном режиме в данный момент. Я не делал прыжок так или иначе, я планировал работать в реальном режиме, пока не установил обработчик процесса.

Итак, при условии, что я работаю в реальном режиме, что я делаю не так и как это исправить? Мне просто нужна базовая процедура getc, желательно неблокирующая, но я буду проклят, если Google поможет в этом. Как только я смогу это сделать, я смогу сделать все остальное.

Я предполагаю, что я спрашиваю здесь, я где-нибудь рядом с правильным путем? Как вообще можно получить ввод с клавиатуры на этом уровне?

РЕДАКТИРОВАТЬ: Оооо ... так что я работаю в защищенном режиме. Это, безусловно, объясняет сбой при попытке получить доступ к функциям реального режима.

Итак, я думаю, что я ищу, как получить доступ к вводу-выводу клавиатуры из защищенного режима. Я мог бы найти это сам, но если кто-то узнает, не стесняйтесь. Еще раз спасибо.

Ответы [ 7 ]

4 голосов
/ 20 октября 2008

Если вы компилируете с помощью gcc, если вы не используете сумасшедший трюк ".code16gcc", который использует ядро ​​linux (в чем я очень сомневаюсь), вы не сможете работать в реальном режиме. Если вы используете мультизагрузочную спецификацию GRUB, GRUB сам переключается в защищенный режим для вас. Так что, как отмечали другие, вам придется напрямую общаться с 8042-совместимым контроллером клавиатуры / мыши. Если только это не клавиатура / мышь USB и эмуляция 8042 отключена, где вам потребуется стек USB (но вы можете использовать «загрузочный» протокол для клавиатуры / мыши, что проще).

Никто не говорил, что писать ядро ​​ОС было просто.

4 голосов
/ 20 октября 2008

Код, который вы получили, пытается получить доступ к службе BIOS реального режима. Если вы работаете в защищенном режиме, который, вероятно, предполагает, что вы пишете ядро, то прерывание не будет работать. Вам нужно будет выполнить одно из следующих действий:

  • Переведите процессор в реальный режим, убедитесь, что таблица векторов прерываний верна, и используйте код реального режима, который у вас есть, или
  • Напишите свой собственный обработчик клавиатуры защищенного режима (т.е. используйте инструкции ввода / вывода).

Первое решение будет связано с накладными расходами во время выполнения, а второе потребует некоторой информации о вводе-выводе клавиатуры.

1 голос
/ 30 октября 2008

В целях объяснения, давайте предположим, что вы писали все на языке ассемблера самостоятельно, загрузчик и ядро ​​(* кашель * Я сделал это).

В реальном режиме вы можете использовать подпрограммы прерывания, поступающие из BIOS. Вы также можете заменить векторы прерываний своими собственными. Однако весь код является 16-битным кодом, который не двоично совместим с 32-битным кодом.

Когда вы перепрыгиваете через несколько горячих обручей, чтобы перейти в защищенный режим (включая перепрограммирование контроллера прерываний, чтобы обойти тот факт, что IBM использовала зарезервированные Intel прерывания в ПК), у вас есть возможность настроить 16- и 32-битные сегменты кода. Это может быть использовано для запуска 16-битного кода. Таким образом, вы можете использовать это для доступа к прерыванию getchar!

... не совсем. Чтобы это прерывание работало, вам действительно нужны данные в буфере клавиатуры, который был помещен туда другим ISR - тот, который запускается клавиатурой при нажатии клавиши. Существуют различные проблемы, которые в значительной степени мешают использовать BIOS ISR в качестве реальных аппаратных ISR в защищенном режиме. Таким образом, процедуры клавиатуры BIOS бесполезны.

Видеозвонки BIOS, с другой стороны, хороши, потому что нет аппаратно-запускаемого компонента. Вам нужно подготовить 16-битный сегмент кода, но если он находится под контролем, вы можете переключать режимы видео и тому подобное, используя прерывания BIOS.

Возвращаясь к клавиатуре: вам нужно (опять же, при условии, что вы пишете весь код), это написать драйвер клавиатуры. Если вы не мазохист (я один), тогда не ходите туда.

Предложение: попробуйте написать многозадачное ядро ​​в реальном режиме. (Это 16-битный режим.) Вы можете использовать все прерывания BIOS! Вы не получаете защиту памяти, но вы все равно можете получить преимущественную многозадачность, перехватывая прерывание таймера.

1 голос
/ 20 октября 2008

Вы все делаете правильно, но я, кажется, напоминаю, что djgpp генерирует только выходные данные защищенного режима, из которых нельзя вызывать прерывания. Можете ли вы перейти в реальный режим, как предлагали другие, или вы бы предпочли обратиться к аппаратному обеспечению напрямую?

1 голос
/ 20 октября 2008

У меня есть часть GeekOS, которая, кажется, делает

In_Byte(KB_CMD);

, а затем

In_Byte(KB_DATA);

чтобы получить скан-код. Я поднял это: keyboard.c и keyboard.h KB_CMD и KB_DATA равны 0x64 и 0x60 соответственно. Я мог бы также отметить, что это делается в обработчике прерываний для intr: 1.

0 голосов
/ 09 мая 2014

Пример опроса контроллера клавиатуры:

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
0 голосов
/ 20 октября 2008

Просто идея: глядя на GRUB для источника DOS (asm.s), функция console_checkkey использует BIOS INT 16H Function 01, а не функцию 00, как вы пытаетесь это сделать. Возможно, вы захотите проверить, ожидает ли ключ ввода.

Код console_checkkey устанавливает процессор в реальный режим для использования BIOS, как предложено @ skizz .

Вы также можете попробовать использовать функции GRUB напрямую (если все еще отображается в реальном режиме).

Примечание по чтению источника сборки: в этой версии

movb    $0x1, %ah

означает перемещение постоянного байта (0x1) в регистр %ah

console_checkkey от 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
...