Как получить ввод с клавиатуры с голой металлической сборкой x86?

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

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

Все исследования, которые я провел, похоже, указывают на ISR по адресу $ 0x16 для чтения следующего символа из буфера клавиатуры. Насколько я могу судить, здесь предполагается хранить значение ASCII в ah, а код клавиши - в 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 поможет в этом вообще. Как только я смогу это сделать, я смогу сделать все остальное оттуда.

Думаю, я спрашиваю, нахожусь ли я на правильном пути? Как вообще добиться ввода с клавиатуры на этом уровне?

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

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


person Nicholas Flynt    schedule 20.10.2008    source источник


Ответы (7)


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

Никто не сказал, что написать ядро ​​ОС - это просто.

person CesarB    schedule 20.10.2008
comment
Обратите внимание, что пока вы остаетесь в защищенном режиме, а не в длительном, вы должны иметь возможность использовать виртуальную задачу 8086 для выполнения прерываний BIOS. (Необработанный ввод-вывод клавиатуры, однако, относительно прост, и, вероятно, более целесообразно просто взаимодействовать с оборудованием напрямую, как предлагает @CesarB.) - person bcat; 29.07.2010

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

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

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

person Skizz    schedule 20.10.2008

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

In_Byte(KB_CMD);

а потом

In_Byte(KB_DATA);

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

person Anders Eurenius    schedule 20.10.2008

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

person Brian Knoblauch    schedule 20.10.2008

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

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

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

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

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

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

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

person Artelius    schedule 30.10.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
person gimel    schedule 20.10.2008

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

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
person Dirk Wolfgang Glomp    schedule 09.05.2014