Пишем игрушечную ОС (часть II) |
Часть I опубликована в апрельском номере журнала. Следующее, что необходимо разобрать после изучения процесса создания загрузочного сектора и до того, как мы перейдём к описанию приёмов переключения в защищённый режим, это использование прерываний BIOS[1]. Прерывания BIOS представляют собой подпрограммы низкого уровня, облегчающие работу создателю операционной системы. В этой части статьи мы будем иметь дело с ними. 1. Теория1.1 Почему BIOS ?BIOS копирует загрузочный сектор в оперативную память и передаёт на него управление. Кроме этого, существует ещё несколько функций, которые могут выполняться BIOS'ом. В момент загрузки операционная система ещё не располагает драйверами для поддержки оборудования. Размещение такого драйвера в загрузочном секторе -- задача практически невыполнимая. Должен существовать другой способ решить эту проблему и в этом нам поможет BIOS. Он содержит множество подпрограмм, служащих для различных целей и которыми мы можем воспользоваться. Например, существуют подпрограммы проверки установленного оборудования, подпрограммы управления выводом на печать, определения размера оперативной памяти и пр. Эти подпрограммы называются подпрограммами или обработчиками прерываний BIOS. 1.2 Как же вызывать прерывания BIOS ?В "обычных" языках программирования вызов
подпрограммы реализуется через обращение к её имени. К
примеру, если в программе на C у нас есть подпрограмма
Например, для вывода символов на экран в C мы используем функцию похожую на:
Эквивалентно этому, оперируя средствами ассемблера и BIOS, мы напишем:
1.3 Ладно, а как мы передаём параметры ?Перед тем как вызвать прерывание BIOS, нам нужно загрузить данные в заранее определённом формате в регистры процессора. Предположим, мы используем прерывание 0x13, предназначенное для чтения/записи с дискеты. Прежде чем вызвать его, мы должны определить адрес в оперативной памяти, куда будут загружены данные. Также мы должны передать информацию о номере устройства (fd0 - 0x00, fd1 - 0x01, hda - 0x80, hdb - 0x81 и т.д.), цилиндре, секторе и количестве копируемых секторов. Эти данные должны быть загружены в определённые регистры. Всё это вам станет понятно после того, как вы прочтёте описание работы кода загрузочного сектора, который мы разработаем чуть позже. Есть одна очень важная деталь, о которой вы должны знать
-- одно и тоже прерывание может использоваться для различных
целей. Всё это зависит от номера функции, который указывается
в регистре 2. Что мы будем делать теперь ?На этот раз наш исходный код состоит из двух программ на
ассемблере и одной на C. Первый файл (на ассемблере) -- это
код загрузочного сектора. В нём хранятся инструкции,
копирующие второй сектор флоппи-диска в сегмент памяти
3. Загрузочный секторИспользуя прерывание 0x13, код загрузочного сектора читает
и копирует второй сектор флоппи-диска в память по адресу
0x5000 (сегментный адрес 0x500). Пример этого показан ниже.
Сохраните его в файле
Первая строка -- это макро-определение. Следующие две
инструкции уже знакомы вам по предыдущей статье. Записать
данные непосредственно в регистры сегментов нельзя, поэтому
следующие две строки используются для загрузки в регистр
Далее мы записываем...
Итак, мы загружаем второй сектор нулевой дорожки
устройства номер 0 (что соответствует приводу флоппи-дисков
на 1.44Мб) по адресу Значение 2 в регистре Теперь мы вызываем прерывание 0x13 и последней командой
передаём управление коду, загруженному по адресу
4. Второй секторВторой сектор будет содержать следующий код :
Этот код загружается и выполняется в сегменте
Первые три строки кода (отсчёт начинается с третьей
строки, пропуская инструкции определения точки входа)
используются для получения текущей позиции курсора. Для этого
используется функция 0x03 прерывания
Начало сообщения содержит два байта со значениями 13 и 10,
что соответствует нажатию клавиши 5. Программа на CКод программы на C, являющийся "ракетоносителем"
(точнее "программоносителем" 8-), приведен ниже.
Сохраните его в файле
В первой части статьи я описал, как создать загрузочную
дискету. В данном примере есть небольшие отличия. Сперва мы
копируем в загрузочный сектор файл 6. Готовые примерыВы можете взять исходники примеров здесь Удалите у файлов расширение
в ответ на приглашение оболочки или вы можете откомпилировать файлы самостоятельно. В этом случаем введите
и повторите тоже самое для
и вставив дискету в дисковод выполните программу
7. Что дальше ?После загрузки с дискеты вы можете любоваться строкой на экране. И всё это благодаря прерываниям BIOS. В следующей статье из этой серии я надеюсь написать о том как переключать процессор в защищённый режим. А до тех пор, пока! |
Krishnakumar R.Кришнакумар -- студент последнего курса B.Tech в Govt. Engg. College Thrissur, Kerala, Индия. Его путешествие в земли Операционных Систем началось с программирования модулей для Linux. Он создал операционную систему GROS, основная цель которой -- выполнение функций маршрутизатора. (Детали вы можете найти на его домашней странице: www.askus.way.to ) Другие его интересы -- сетевые драйвера, драйвера устройств, портирование компиляторов и встроенные системы. |
Примечания переводчика[1] BIOS -- Basic Input/Output System (Базовая Система Ввода/Вывода), код прошиваемый в ПЗУ и позволяющий работать с оборудованием компьютера. [2] Чтобы получить абсолютное
значение адреса из адреса в формате сегментной адресации,
нужно умножить значение сегментного регистра на 0x10 и
прибавить величину смещения. В нашем случае это
[3] Автор не стал объяснять почему
в регистр [4] На мой взгляд, необходимо немного изменить эту программу -- убрать явное указание количества символов в строке, заменив его вычислением. Т.е. вместо строки
ставим две других
и добавляем в конце программы метку
[5] Если быть точным, то на адрес
строки указывает пара регистров -- [6] Для любителей простоты исполнения, код программы на C может быть заменён скриптом на bash'е из двух строк (точнее трёх -- есть ещё заголовок:)
Хотя опция |
Copyright (С) 2002, Krishnakumar R.
|
Вернуться на главную страницу |