Недокументированная команда LOADALL
Оказывается, для процессора i80286 существует способ получения доступа к расширенной памяти, не переключаясь в защищённый режим. Для этого может быть использована недокументированная команда LOADALL, имеющая код 0F05h (команда не имеет операндов). Эта команда не описана в справочниках по процессору i80286, информация о ней поставляется фирмой Intel по запросу. Те сведения о команде LOADALL, которые приведены в нашей книге, получены по электронной почте из BBS и могут быть использованы только для расширения вашего кругозора и для оценки полезности этой команды в ваших разработках.
Команда LOADALL первоначально была задумана фирмой Intel как тестовая. Однако оказалось, что она пригодна и для обращения к расширенной памяти в реальном режиме. Широко известный драйвер расширенной памяти HIMEM.SYS обращается в область адресов выше первого мегабайта именно с помощью команды LOADALL (а не переключаясь в защищённый режим и возвращаясь обратно, как это можно было бы предположить).
Команда LOADALL сокращает время, требуемое драйверу HIMEM.SYS на доступ к расширенной памяти, так как время на переключение в защищённый режим и обратное переключение достаточно велико по сравнению с временем, необходимым на копирование данных из основной памяти в расширенную или обратно.
Другое применение команды - драйвер электронного диска Microsoft RAMDRIVE.SYS и блок совместимости операционной системы Microsoft OS/2 версии 1.x.
Секрет команды LOADALL заключается в том, что она загружает ВСЕ регистры процессора, и может выполняться в реальном режиме. Изменяя поле базы регистра кэша дескриптора (внутренний системный регистр процессора) программа может обратиться к сегменту, лежащему за пределами первого мегабайта адресного пространства.
Как мы уже говорили, команда LOADALL не имеет операндов. Регистры загружаются из буфера, который имеет длину 102 байта и должен быть подготовлен в области памяти с физическим адресом 00800h.
Формат буфера представлен в следующей таблице:
Таблица 16. Формат буфера для команды LOADALL.
Адрес | Регистры процессора |
800h-805h | Не используется |
806h-807h | Слово состояния процессора MSW (Machine Status Word) |
808h-815h | Не используется |
816h-817h | Регистр задачи TR (Task Register) |
818h-819h | Регистр флагов |
81Ah-81Bh | Регистр IP (Instruction Pointer) |
81Ch-81Dh | Селектор LDT (Local Descriptor Table) |
81Eh-81Fh | Регистр DS (Data Segment Selector) |
820h-821h | Регистр SS (Stack Segment Selector) |
822h-823h | Регистр CS (Code Segment Selector) |
824h-825h | Регистр ES (Extra Segment Selector) |
826h-827h | Регистр DI (Destination Index) |
818h-829h | Регистр SI (Source Index) |
82Ah-82Bh | Регистр BP (Base Pointer) |
82Ch-82Dh | Регистр SP (Stack Pointer) |
82Eh-82Fh | Регистр BX (Data Register BX) |
830h-831h | Регистр DX (Data Register DX) |
832h-833h | Регистр CX (Data Register CX) |
834h-835h | Регистр AX (Accumulator) |
836h-83Bh | Кэш дескриптора ES |
83Ch-841h | Кэш дескриптора CS |
842h-847h | Кэш дескриптора SS |
848h-84Dh | Кеш дескриптора DS |
84Eh-853h | Регистр GDTR (Global Descriptor Table Register) |
854h-859h | Кэш дескриптора LDT |
85Ah-85Fh | Регистр IDTR (Interrupt Descriptor Table Register) |
860h-865h | Кэш дескриптора TSS (Task State Segment) |
Формат кэша дескриптора приведён в следующей таблице:
Таблица 17. Формат кэша дескриптора.
Смещение поля | Назначение поля |
0-2 | 24-битовый базовый адрес сегмента |
3 | Байт доступа, его формат полностью аналогичен формату байта доступа дескриптора, за исключением бита присутствия. На месте этого бита находится бит VALID. Если этот бит сброшен в 0, при попытке использовать дескриптор для адресации памяти произойдёт исключение 13 с кодом ошибки 0. |
4-5 | 16-битовый предел сегмента |
Можно предложить следующий алгоритм использования команды LOADALL:
- Запретитите прерывания.
- Сохраните где-нибудь в буфере программы область памяти, начинающуюся с адреса 00800h и имеющую длину 102 байта.
- Заполните буфер для команды LOADALL необходимыми значениями для всех загружаемых регистров. Базовый адрес в области кэша дескриптора сегмента данных должен указывать на необходимый вам участок расширенной памяти.
- Выполните команду LOADALL. Сегмент данных теперь будет указывать на область расширенной памяти.
- Выполните запись или чтение области расширенной памяти.
- Восстановите базовый адрес сегмента данных в кэше дескриптора данных в буфре, расположенном по адресу 00800h.
- Выполните команду LOADALL ещё раз.
- Восстановите содержимое сохранённого ранее буфера.
- Разрешите прерывания.
Команда LOADALL может выполняться в защищённом режиме в нулевом приоритетном кольце. Но, к сожалению, эту команду нельзя использовать для переключения процессора из защищённого в реальный режим.
Процессор i80387 также имеет команду LOADALL, но её код и выполняемые функции другие.