О природе вещей
Название данного материала может показаться странным. Операционная система
MS-DOS, традиционно ассоциируемая с 16-битными процессорами и программами, уже
давно вышла из широкого употребления на персональных компьютерах и забыта
многими пользователями как безнадежно устаревшая. В то же время, несмотря на то,
что прошло более 5 лет с момента выхода 64-битных процессоров x86, время
полноценного использования 64-битных вычислений на платформе PC еще не пришло.
Так в чем же смысл совмещения этих двух представителей разных эпох: старой
16-битной системы MS-DOS и нового 64-битного режима работы процессора?
Представим себе специалиста, область интересов которого находится на границе
аппаратного и программного обеспечения. Это может быть системный программист,
занимающийся написанием BIOS или диагностического программного обеспечения,
которому нужно отладить процесс взаимодействия процедур программы с аппаратурой.
Также это может быть разработчик микросхем чипсета, которому требуется выполнить
ряд испытаний: например программно сформировать некоторое управляющее
воздействие (записать данные в регистры управления) и проконтролировать
результат (прочитать данные из регистров статуса). В отличие от прикладного
программирования, для такой задачи важно понимание процесса выполнения программы
на уровне принципиальной электрической схемы, генерации сигналов и выполнения
транзакций на системной шине процессора при выполнении ассемблерных команд.
Для перечисленных выше примеров система DOS удобна тем, что в силу своей
простоты и компактности, она, в отличие, например от Windows, имеет высокие
шансы запуститься на частично работоспособной (отлаживаемой) системе. Она не
требует процедуры повторной инсталляции, если мы заменяем отлаживаемую плату,
что важно в случаях, когда через отладку проходят десятки и сотни плат различных
моделей. Но главное не в этом.
Известно, что одним из важнейших свойств многозадачных ОС является
способность сохранять устойчивость ОС при различных сбоях внутри приложений. Для
этого ОС существенно ограничивает набор операций, которые позволено выполнять
приложениям. Например, если пользовательская программа (user) попытается
напрямую обратиться к регистрам системных устройств, операционная система
(supervisor) перехватит данное обращение и запрошенная операция не состоится.
При этом ОС выполнит эмуляцию или выдаст сообщение об ошибке. Оба варианта
неприемлемы, если наша задача - отладка взаимодействия программы с регистрами
чипсета или системными регистрами процессора.
Здесь читатель может возразить и сказать, что существуют методы обхода такой
защиты. Да, это так, но будет ли польза от этого в нашем случае? Мы обойдем
защиту и выполним интересующую нас перенастройку чипсета. После этого, с высокой
вероятностью в результате перенастройки чипсета “зависнет” весь Windows и нам
останется только нажать RESET.
В свою очередь, если мы работаем под ”чистым” DOS, у нас нет необходимости
обходить какие-либо защиты, наша программа сама включает Protected Mode и
является супервизором, она может монопольно взаимодействовать с любым
программно-доступным ресурсом. Мы можем контролировать выполнение программы на
уровне ассемблерных команд и машинного кода. В силу своей простоты и
компактности, DOS имеет существенно меньшую вероятность “зависания” при
выполнении различных нестандартных экспериментов с оборудованием.
Конечно, здесь тоже есть свои границы дозволенного. Если мы, например,
перепрограммируем тактовый генератор и выключим тактирование процессора,
зависнет и DOS.
Что предлагается
Автор реализовал переключение процессора в 64-битный режим на ассемблере под
DOS, то есть “с нуля”. Публикуемый исходный текст может быть использован
программистами как шаблон для исследовательских работ и написания собственных
процедур. Программа подготавливает контекст (генерирует таблицы дескрипторов
сегментов и страниц, устанавливает содержимое системных регистров процессора), и
переключает процессор в режим IA32e. В этом режиме приобретает функциональность
ранее зарезервированный бит 53 (бит L=Long Mode) дескриптора сегмента кода:
межсегментная передача управления вызывает переключение процессора в 64-битный
режим, если в дескрипторе целевого сегмента кода бит L=1. Иначе, если L=0,
процессор остается в 32-битном режиме. В предлагаемой программе выполняется 2
примера: вызов 32-битной целевой процедуры из сегмента, в дескрипторе которого
L=0 и вызов 64-битной целевой процедуры из сегмента, в дескрипторе которого L=1.
Для контроля результатов, автор поместил в тело целевых процедур инструкции,
сохраняющие результаты в памяти. Данные результаты могут быть проконтролированы
путем выполнения дампа буфера при работе под отладчиком.
Как было сказано выше, публикуемый исходный текст является шаблоном,
содержимое целевых процедур может быть модифицировано или переписано
пользователем в соответствии с его задачами.
Абсолютно все операции, связанные с переключением в 64-битный режим и
созданием контекста для работы в нем, явно присутствуют в виде ассемблерных
команд и блоков данных. В то время как, изучая данный вопрос под Windows и
используя языки программирования высокого уровня, мы многое упускаем, так как
большую часть работы за нас делают Windows и компилятор.
Кому это интересно
Данный материал адресован следующей аудитории:
- Специалисты, область интересов которых находится на границе аппаратного и
программного обеспечения. - Программисты, занимающиеся разработкой операционных систем “с нуля”.
- Программисты, занимающиеся разработкой специализированного программного
обеспечения для диагностики и верификации PC. Если такое программное
обеспечение будет компактным и самодостаточным, то у него значительно больше
шансов запуститься на диагностируемой частично исправной системе и выполнить
свои функции, чем например у Windows-приложения, так как на частично исправной
системе не запустится сам Windows. - Преподаватели и студенты технических вузов. Актуально для специальностей,
связанных с программированием на языке ассемблера, изучением архитектуры
64-битных процессоров и аппаратного обеспечения компьютера.
Предполагается, что читатель знаком с программированием на языке ассемблера
для 16-ти и 32-битной архитектуры x86 с использованием программ фирмы Borland:
Turbo Assembler (TASM) 3.0, Turbo Linker (TLINK) 4.0, Turbo
Debugger 2.51. В целях компактности изложения, в описании программы детально
прокомментированы только те аспекты, которые имеют отношение к 64-битному
режиму.
Организация рабочего места
Для запуска предлагаемых фрагментов, вам потребуется “чистая” DOS-среда.
Подойдет MS-DOS версий 5, 6 или DOS, поставляемая в составе Windows 98.
Процессор должен работать в реальном режиме (Real Mode), следует отключить
менеджеры памяти EMM386, QEMM. Разумеется, в DOS-окне под Windows предлагаемые
эксперименты не могут быть выполнены. Для удобства, рекомендуется использовать
файловый менеджер, например Volkov Commander (VC). Следующие программы фирмы
Borland должны присутствовать на диске и на них должен быть установлен путь
оператором PATH в AUTOEXEC.BAT: Turbo Assembler (TASM) 3.0, Turbo
Linker (TLINK) 4.0, Turbo Debugger 2.51. Хотя, опытный пользователь
может использовать другую среду по своему усмотрению.
Процессор должен поддерживать 64-битное расширение для x86: AMD64 или Intel
EM64T.
Так как предлагаемая программа является “полуфабрикатом”, подразумевается,
что предварительную проверку режима работы процессора (Real или Protected), а
также идентификацию процессора и проверку наличия поддержки 64-битного режима
при необходимости пользователь может реализовать самостоятельно.
Экспериментировать с ассемблерным кодом будет значительно удобнее при наличии
устройства POST Card (Port 80h). Данное устройство обычно используется
при диагностике материнских плат и отображает так называемые POST коды,
формируемые BIOS. Физически, POST Card - это 8-битный порт вывода (регистр) с
адресом 0080h снабженный 2-разрядным 7-сегментным индикатором, работающим в
шестнадцатеричной системе (00h-FFh) и отображающим код, записанный в регистр.
Устройства POST Card выпускаются в вариантах для установки на шину ISA или PCI.
На некоторых материнских платах они интегрированы. Данное устройство удобно для
расстановки контрольных точек в программе при локализации места “зависания”, так
как для вывода контрольной точки достаточно двух ассемблерных команд:
MOV AL, Check_Code
OUT 80h,AL
Если при выполнении отлаживаемой секции программы, компьютер не “зависает”, а
перезапускается, и нет возможности пронаблюдать код на индикаторе и определить,
дошло ли выполнение до заданной точки, рекомендуется выполнить запрет прерываний
и останов после вывода кода:
MOV AL, Check_Code
OUT 80h,AL
CLI
HLT
Если выполнение дошло до данной точки, процессор остановится и на индикаторе
будет отображаться код Check_Code.