Низкоуровневый АД: пишем свою ОС — Часть 2. Модули и ввод
Всем здрасте, и сегодня у нас продолжение низкоуровневого программирования. В этой части мы все разобьем на модули, а так же напишем ввод, благодаря чем мы сможем сделать маленькую командную оболочку!
Шаг 1. Модули
Для более читабельного кода я решил сделать папочку kernel/lib, в которой у нас будет три файла: stdio.h, types.h, string.h. В первом уже понятно - ввод-вывод, во втором типы, в третьем работа со строками.
В stdio.h мы пишем сначала 2 функции - printc() и printl(), которые выводят символ и строку соответственно
Первая функция - это как строки с выводом с ядре - в видеопамять (которая как аргумент ведь адрес может отличаться) мы записываем по индексу номер символа (порядковый) * 2 сам символ, а в номер*2+1 - цвет. В printl() же всего три аргумента - адрес видеопамяти, текст и.... начальный символ. Ведь текст может быть после предыдущего вывода. Кстати указатель на следующий после текста символ возвращается. Тут все просто - просто в цикле вызываем printc().
Дальше - интересней. Пишем ввод
В первой функции мы получаем данные с порта через ASM и возвращаем их. Во второй - получаем данные с порта состояния PS/2 (да-да, старый добрый разъем, не USB, там надо писать ого-го!), смотрит на бит готовности, и так по циклу пока не будет бит равен 1; дальше возвращается сама клавиша.
На заметку
В types.h почти ничего нет - просто пишем один typedef
В string.h тож ничего особенного - просто функция для подсчета символов в строке
Шаг 2. Пишем ввод в ядре
А сейчас, реализовав вывод и ввод, мы можем включить это в наше ядро. Но для этого нам потребуется проанализировать, при нажатии какой клавиша какой символ будет. Поэтому:
Меняем код вывода на этот (тут вывод и ввод смивола) (а также не забудьте подключить нашу библиотеку (#include "stdio.h")
Сообщение можете взять мое, а можете свое
Вставляем ниже код для отображения сканкода:
Компилируем (скрипт есть, но не забудьте к i686 прибавить -I kernel/lib)
Запускаем и пробуем нажать клавишу
Идем на OSDev Wiki и ищем там наш код
Если клавиша которую вы нажали сходится с клавишей которая указана в таблице - значит у вас этот code scan set (у меня первый набор)
После этого можно идти и писать обработчик.
Мы создадим специальную функцию (в stdio.h) которая будет превращать символы из сканкодов в символы которые написаны на клавиатуре
Функция как возвращает, так и принимает символ (который из сканкода получается), дальше по кругу проверяет со символами из 1-го массива, если равен, возвращает соответственный по позиции символ из 2-го массива (нажатая клавиша). А если не нашло в 1-м массиве наш символ, то мы его же и возвращаем. Обработчик сам-то несложный, но массивы получаются достаточно большими, а это еще мы не обрабатывали нажатие с CapsLock и Shift, поэтому я привел более упрощенный вариант.
Меняем в ядре строчки вывода и пустой цикл на
А теперь компилируем, и смотрим что получается
Странно как-то. Вроде клавишы обрабатываются, но за ними потом идет еще символ. Странно, да? А теперь попробуйте зажать. Нету того символа, да? Так вот в чем проблема: мы обрабатывали прерывание с отпусканием клавишы, и оно посылало сканкод 0x80 + сканкод клавишы. Давайте вернемся в stdio.h и вместо return inb(0x60); напишем данный код:
Он игнорирует отпускание клавишы. А теперь в kernel.c после получение символа с клавиатуры:
Чтобы пробел не выводился после каждого символа мы добавляем этот код (все равно сканкода 0x00 нету)
Запускаем откомпилированный и собранный в ISO файл - и вуаля
Ну надеюсь вы сможете дописать обработку всех клавиш. А давайте пока составим план на следующие части:
- Сделать командную оболочку
- Реализовать там функции echo, shutdown и version
Ссылки:
- Гитхаб - https://github.com/KirillMos2/HabrOS/
Спасибо что прочитали! Буду дальше писать ОС.
(примечание: это копия с еще неопубликованной статьи на хабре)