Text
                    иблиотека
»!
1'и.
Pej
в]
ш]
1ИЩЕННЫИ
РЕЖИМ
ПРОЦЕССОРОВ
Intel 80286/80386/804
«чЯ истемного
LJ рограмми ста

/1ИИИОГЛ1И0И


БИБЛИОТЕКА СИСТЕМНОГО ПРОГРАММИСТА шестой том А.В. ФРОЛОВ, Г.В. ФРОЛОВ защищённый режим процессоров Intel 80286/80386/80486 Практическое руководство по использованию защищённого режима МОСКВА - "ДИАЛОГ-МИФИ" в 1993
»БК 32.973 Ф91 ’ БИБЛИОТЕКА СИСТЕМНОГО ПРОГРАММИСТА Выпускается с 1991 года Фролов А.В., Фролов Г.В. Ф91 Защищённый режим процессоров Intel 80286, 80386, 80486. Практическое руководство, по использованию защищённого режима.— М.: ’’ДИАЛОГ-МИФИ”, 1993. — 240 с. — (Библиотека системного программиста; Т. 6) ISBN 5-86404-032-0 (Т. 6) Учебно-справочное пособие. Имеет практическую направленность. В книге описаны особенности защищённого режима работы процессора, процедура переключения в защищённый режим и возврата в реальный режим. Приведены программы, демонстрирующие использование защи- • щённого режима и мультизадачное.. Описана, иерархия средств для ра- боты в защищённом режиме, в частности, интерфейсы прерывания BIOS INT 15h, VCPl, DPMI, DOS-экстендеры и виртуальная машинд операци- онной системы WINDOWS 2404070000-005 ‘ Ф------Г70(03)-93---- Б“ БВК 32.973 ' >• Учебно-справочное издание , Фролов Александр Вячеславович ' '. Фролов Григорий Вячеславович Защищённый режим процессоров Intel 80286, 80386, 80486. Практическое руководство по использованию защищённого режима !й Макет О.А. Кузьминовой Обложка Н.В. Дмитриевой Корректор В.С. Кустов Подписано в печать 20.09.93. Формат 60x84/16- Печать офсетная. Усл. печ. л. 13.95. Уч.-изд. л. 11.65. Тираж 20 000 экз. Заказ 9SH. Акционерное общество "ДИАЛОГ-МИФИ” 115409, Москва, ул. Москворечье, 31, корп. 2 Подольский филиал Чеховского полиграфического комбината 142100, г. Подольск. Московская обл., ул. Кирова, 25 ISBN 5-86404-032-0 <Т. 6) ISBN 5-86404-004-5 ©А.В. Фролов, Г.В. Фролов, 1993 © Оригинал-макет, оформление обложки. АО "ДИАЛОГ-МИФИ”, 1993
ВВЕДЕНИЕ Книга представляет собсй введение ь программирование для зашклёнизпо ре- жима широко распрострачённых процессоров Intel 80286/80386/80486. В отли- чие от зарубежных авторов аналогичных книг, переведённых на русский язык, мы сконцентрировали внимание на практической стороне использования защи- щенного режнха работы процессоров В к1 иге приведено большое количество программ, составленных на языках Си и ассемблера, и вы сразу сможете прове- рить полученные знания на практике. Все описанные программы записаны на ди- скете, которую можно купить дополнительно. Программы подготовлены в среде Borland С 3.0. но м:жно вост льзош ться и Borland С 2.0 или BcrLand С 3.1.' Приведённые примеры нетрудно адаптировать для транслятора Microsoft Quick С. Каша книга ке похожа и справочник по процессорам i80286 и i80386 - подо- бной литературы издано достаточно и она доступна. К тому же для составления работоспособных программ защищён н:го режима недостаточно владеть тольк? информацией з работе процессе ра, нужны ещё знания некоторых аппаратных особенностей персональною компьютера и особенностей используемых операци- онных систем. Поэтому мы не стремились описать тонкости работы всех команд процессора в защищённом режиме - всё это есть в справочниках. Мы приведём сведения, которые позволят сразу приступить к состав/ению собственных прог- рамм, работающих в защищённом режиме, в частности драйверов аппаратуры и мультизадачных мониторез, программ, активно работающих с большими масси- вами данных. За основу вы можете взять примеры программ из книги. Для тех, кто ещё не знаком с защищённым режимом работы, скажем, что этот режим является основным и естественным режимом работы процессоров i80286, i80386 и 1'80486. Только в защищённом режлме полностью реализуются все воз- можности, заложенные в архитектуру процессоров. Защищённый режим работы используется во мне тих программных продуктах, таких как операь конные сис- темы UNIX, XENIX, OS/2, PC-MOS, QNX, Desk View, сетевых операционных системах NOVELL, в операционной системе Microsoft WINDOWS, в драйвера! расширенной памяти EMM386 и QEMM, в СУБД ORACLE. Хорошо известная система разработки программно:^ обе течения Borland С также может работав в защищённом режиме, при этом её производительность заметно возрастает. Перспективна! операционная система Microsoft WINDOWS NT также используе- защищёвный режим работы процессора В настоящее время в области программного обеспечения прослеживается тен- денция ориентации на оболочку Microsoft WINDOWS, пользующуюся огромной популярностью го всём мире. Однако нс все знают, что Microsoft WINDOWS - это не только прекрасная графика, продуманный дизайн и удобство в работе. Все программы, разрабатываемые для WINDOWS, работают в защищённом режиме, и они используют всю мощь современных процессоров и все возможности ком- пьютера (в отличие от прщрамм, ориентированных только на MS-DOS). •диалог-мифи' 1
Защищённый режим процессоров Intel 80286/80386/80486 Поэтому если вы планируете составлять программы для WINDOWS, вам необ- ходимо знать особенности работы процессора в защищённом режиме. Особенно если вы будете разрабатывать драйверы или другие программы, работающие^ аппаратурой, либо если ваши программы будут обрабатывать большие масомц* данных (порядка нескольких мегабайт или даже нескольких десятков мега Наша книга может стать для вас первым шагом к программированию для тизадачных операционных систем, таких, как WINDOWS, OS/2 или UNIX. Наиболее очевидны преимущества защищённого режима для решения з^Двч,, связанных с обработкой больших массивов данных. Например, для обработямУ; графических данных, полученных со сканера, при количестве градаций равном 256, может потребоваться несколько десятков мегабайт оперативной мяти. Механизм так называемой виртуальной памяти, реализованный в процеЫ сорах i80386 и 180486 (и работающий только в защищённом режиме), позволяет; предоставить программам практически неограниченный объём виртуальной опе- ративной памяти, реализованной с использованием магнитного диска. Даже если вы составляете программы, ориентированные только на MS-DOS^ вам всё равно придётся столкнуться с защищённым режимом работы процессоре^ Это связано с тем, что для увеличения доступного программам объёма операти ной памяти часто используются драйверы расширенной памяти EMM386 Ш QEMM. Если установлен один из этих драйверов, процессор работает ухе реальном режиме, а в так называемом режиме "виртуального процессора 8086^ (в который он попадает из защищённого режима). Если ваша программа (пр назначенная для работы в MS-DOS) запущена в среде WINDOWS в режиме * Enhanced Mpde", она также будет выполняться процессором в режиме "вир ального процессора 8086”. Если при разработке программы, ориентированной на MS-DOS, не прииимн во внимание возможность работы на "виртуальном процессоре”, она может м заться несовместимой с WINDOWS или драйверами EMM386 и QEMM. Таким образом, разрабатывая программу для MS-DOS, вам следует про вопросы совместимости с драйверами расширенной памяти и оболоч WINDOWS. А для этого вы должны знать особенности защищённого ре режима виртуального процессора 8086. Кроме обеспечения корректной работы в виртуальном режиме проц знание особенностей защищённого режима позволит вам полно и эффект использовать такой ресурс компьютера, как расширенная оперативная память. О содержании книги В первой главе книги мы приводим основные теоретические сведения о раб) процессора в защищённом режиме. При этом мы не претендуем на полноту сания возможностей процессора. На этом этапе наша цель - дать минимум ний, необходимых для того, чтобы приступить к составлению первых пр огры работающих в защищённом режиме. В списке литературы есть ссылки на спр чнихи и другие книги, в которых описана работа всех команд в защищённой жиме и приведены форматы всех регистров. Мы же сконцентрируем вниманий
Введение 5 практическом использовании защищённого режима в компьютере IBM ЛТ и дру- гих компьютерах, выполненных на базе процессоров i80286, i80386,180486. Вторая глава книги содержит простой пример программы, переводящей про- цессор i80286 в защищённый режим и возвращающий его обратно. На примере этой программы вы сможете получить представление о том, как выполняются процедуры входа процессора в защищённый режим работы и возврата в реаль- ный режим работы. Третья глава посвящена прерываниям и исключениям в защищённом режи- ме. Вы поймете разницу между механизмами прерываний реального и защищён- ного режимов, на конкретном примере программы научитесь обрабатывать аппа- ратные и программные прерывания, а также исключения в защищённом режиме. Будут рассмотрены вопросы инициализации контроллера прерываний для работы в защищённом режиме. Четвёртая глава содержит сведения об использовании мультизадачных воз- можностей, реализованных в'процессоре i80286 аппаратно. Мы приведём пример простого мультизадачного монитора и на его примере покажем, как можно орга- низовать разделение процессорного времени между одновременно выполняющи- мися задачами. Кроме того, мы рассмотрим вопросы синхронизации выполнения задач и использование семафоров. Пятая глава посвящена особенностям процессоров i80386 и 180486. Мы рас- скажем об уникальной схеме преобразования адресов, позволяющей программам адресовать практически неограниченный объём памяти. Будут рассмотрены осо- бенности обработки прерываний и мультизадачности, а также режим виртуально- го процессора 8086. В шестой главе описана иерархия средств, доступных обычным DOS-прог- раммам для работы в защищённом режиме. В этой главе описаны средства BIOS, которые программа может использовать для переключения в защищённый режим и для доступа к расширенной памяти, интерфейсы VCPI и DPMI, а также расширители DOS для работы в защищённом режиме - DOS-экстендеры. Интерфейс VCPI (Virtual Control Programm Interface) облегчает составление программ, использующих защищённый режим работы процессоров. Этот интер- фейс доступен в тех случаях, когда в компьютере установлен процессор i80386 или i8O486 и используется драйвер расширенной памяти, аналогичный EMM386 или QEMM. Интерфейс DPMI представляет собой интерфейс более высокого уровня, чем VCPI. Этот интерфейс доступен в среде WINDOWS версий 3.0 или 3.1, работаю- щей в режиме ”386 Enhanced Mode". Седьмая глава посвящена операционной системе Microsoft WINDOWS. Эта операционная система позволяет использовать не только программы, разработан- ные специально для неё, но и обычные DOS-программы. При работе WINDOWS в расширенном режиме ”386 Enhanced Mode” DOS-программы получают допол- нительные возможности. Они могут переключаться в защищённый режим и об- ратно (в режим виртуального процессора 8086), могут обмениваться информа- ‘ДИАЛОГ-МИФИ’
Защищённый режим процессоров Intel 80286/80386/80486 [ией с программами WINDOWS с помощью механизма CLIPBOARD (стандарт- ного для программ WINDOWS механизма обмена информацией). Мы рассмотрим также некоторые вопросы совместной работы резидентных |рограмм DOS и драйверов DOS с операционной системой WINDOWS. Небольшое замечание относительно переориентации программ ’’Библиотеки истемного программиста” на Borland С. Предыдущие тома содержали примеры (рограмм, подготовленные для Microsoft Quick С или Microsoft С 6.0. Начиная с ,етвёртого тома мы решили изменить платформу и расстаться с трансляторами эирмы Microsoft. Это вызвано в основном двумя причинами. Первая носит, если ак можно выразиться, тактический характер, а вторая - стратегический. Политика Borland на российском рынке привела к тому, что стоимость из- делий этой фирмы в рублях значительно ниже стоимости аналогичных продуктов фирмы Microsoft. Это способствует их более широкому распро- странению на рынке. В настоящее время большинство передовых программистов переходит от традиционного программирования к объектно-ориентированному. На рын- ке трансляторов для объектно-ориентированных языков Borland заняла наиболее прочную позицию, в частности, благодаря её последнему изде- лию - Borland C++ 3.1. Чтобы не быть голословными по поводу цен, приведём цены на системы раз- >аботки программного обеспечения по прейскуранту инновационного центра 'Перспективные технологии” от 24 августа 1992. Изделие Цена, руб. Microsoft C/C++ 7.0 126 900 Microsoft QuickC for WINDOWS 51 150 Borland C++ & Appl. Frameworks 3.0 24 000 Borland C++ 3.0 17 100 Комментарии излишни. Что же касается объектно-ориентированного программирования,'то без пре- увеличения можно сказать, что именно благодаря ему фирма Borland заняла ли- щрующее место в области программного обеспечения. Поэтому мы приглашаем читателей "Библиотеки системного программиста” делать первый шаг в направлении объектно-ориентированной технологии - ос- .оить систему программирования Borland С. В дальнейшем мы планируем в на- пих книгах активно пропагандировать объектно-ориентированное программиро- ,ание на языке C++. Авторы выражают благодарность сотруднику АО ’’ДИАЛОГ-МИФИ” Максиму Синеву за ценные рекомендации по содержанию книги р за существенную по- мощь, оказанную при работе над разделом, посвящённым DOS-экстендерам. Мы акже благодарим всех сотрудников АО "ДИАЛОГ-МИФИ", принимавших учас- ие в подготовке книги к изданию.
Глава 1 ОСОБЕННОСТИ ЗАЩИЩЁННОГО РЕЖИМА ПРОЦЕССОРА i80286 Подавляющее большинство владельцев персональных компьютеров, совмести- мых с IBM PC, используют операционную систему Microsoft MS-DOS или анало- гичную (IBM PC DOS или Digital Research DR DOS). Все эти операционные сис- темы изначально разрабатывались для микропроцессора фирмы Intel 18086 или его более дешёвого аналога 18088. Именно такие микропроцессоры были устано- влены в первых персональных компьютерах фирмы IBM - IBM PC и IBM XT. Процессоры i8086 и 18088 относятся к 16-разрядным процессорам. Макси- мальный объём адресуемой ими оперативной памяти составляет 1 Мбайт, что оп- ределяется использованием 20-разрядной адресации памяти. Вы знаете, что разработчики фирмы IBM из всего мегабайтного адресного пространства отвели для оперативной памяти 640 Кбайт, зарезервировав осталь- ное для BIOS и аппаратуры. Именно на такую конфигурацию адресного пространства и рассчитана опера- ционная система MS-DOS (и её аналоги). Поэтому максимальный размер опера- тивной памяти, доступной программам, работающим под управлением MS-DOS, обычно составляет 500 - 620 Кбайт, в зависимости от версии операционной сис- темы и её настройки, от типа компьютера, от конфигурации драйверов и резиде- нтных программ. По мере внедрения персональных компьютеров в различные сферы деятельно- сти человека быстро возрастали сложность программного обеспечения и требова- ния к аппаратуре персонального компьютера. Скоро стало ясно, что для успеш- ного решения многих задач объёма памяти в 640 Кбайт'явно недостаточно. Следующая удачная модель процессора фирмы Intel - 16-разрядный процессор i80286 - принципиально отличается от 18086. Этот процессор может работать в двух режимах - реальном и защищённом. В реальном режиме процессор 180286 является практически полным аналогом 18086, но имеет большее быстродействие. В реальный режим процессор переклю- чается после аппаратного сброса или после включения питания компьютера. . Реальный режим обеспечивает полную совместимость процессора i80286 с программным 'обеспечением, подготовленным для 18086. Поэтому компьютер IBM АТ (и его аналоги), в котором установлен процессор i80286, способен без труда работать с операционной системой MS-DOS и программами, разработан- ным ранее для процессора i8086. Однако полностью возможности i80286 реализуются в так называемом за- щищённом. режиме, в который процессор может переключиться из реального ре- жима специальной командой. В защищённом режиме процессор i80286 полностью преображается. Исполь- зуя совершенно иной метод адресации памяти, процессор i80286 расширяет адре- ’ДИАЛОГ-МИФИ’
I Защищенный режим процессоров Intel 80286/60386/80486 :ное пространство до 1G Мбайт Процессор i80286 в защищённом режиме имеет (строенную поддержку мультизадачных операционных систем, значительно ус- юряющую и упрощающую процесс переключения задач. Эта подд’ржка активно ^пользуется всеми мультизадачными операционными системами и оболочками, (заработанными для компьютера IBM PC/AT. Кроме расширения адресной) пространства, новый метод адресации памяти юзволяет изолировать адресные пространства ттдельных задач друг от друга. 1ри этом прикладная программа, работающая в среде операционной системы, гспсльзующей защищённый режим, не может случайно или намеренно разру- пита целости теть самой операционной системы. Вспомните, сколько раз вам приходилось перезагружать операционную систе- му MS-DOS в процессе отладки резидентных (да и не только резидентных!) про- рамм. Так как в реальном режиме ваша программа может выполнять запись денных по любым адресам в пределах первого мегабайта, ей ничего не стоит за- гасать что-нибудь в область памяти, принадлежащей операционкой системе MS- 305. или испортить векторную таблицу прерываний. В защищённом режиме пренрамма может записывать данные только в те обда- ли памяти, которые выделены ей операционной системой. Это сильно повышает тадежность работы мультизадачных и, г частности, мультипользсвательских опе- )ационных систем. В последнем случае изолирование адресных пространств за- <ач, принадлежащих отдельным пользователям, ь хорошо спроектированной аультипользовательский операционной системе полностью исключает такую си- туацию, когда после запуска одним пользователем нет остаточно отлаженной 1ро1раммы приходится перезапускать всю систему. Вообще говоря, по своим возможностям процессор i80286 в защищённом ре- киме больше похож на центральные процессоры больших и мини-ЭВМ, чем на микропроцессоры, использовавшиеся в первых моделях персональных компью- теров Поэтому i80286 (а также следующие модели - i80386 и 180486) обычно газывают не микропроцессорами, а процессорами. В следующих моделях процессоров фирмы Intel - i80386 и 180486 - помимо )асширения адресного пространства до умопомрачительной величины в 4 Тбайта )еализована гонцепцих страничной виртуальной намята Всё это возможно толь- co в защищённом режиме Не вдаваясь в детали (их мы рассмотрим позже), можно сказать, что меха- шзы страничной вир-уальной памяти позволяет разместить часть оперативной тамяти на диске. В настоящее -.ремя стоимость оперативной памяти такова, что )едко Можно встретить персональные компьютеры, оснащенные более чем 16 Мбайтами оперативной памяти. Обычно же в наличии её имеется всего 3 - 4 Мбайта. Но если ваш компьютер имеет диск большого размера, вы можете за- действовать часть Диска для создания виртуальной оперативной памяти. При пом размер оперативчой памяти (виртуальной), предоставляемой программам, (граничен разве что лишь размером свободного пространства на диске. Например, при работе в среде операционной системы WINDOWS версий 3 0 и 1.1 на компьютерах, оснащённых процессорами i80386 или i80486, в расширен-
Особенности защищенного режима процессора i80286 9 ном хжимс <386 Enhanced Mode; про»рамма может распоряжаться несколькими десятками мегабайт виртуальной оперативной памяти, даже если г компьютере уста -.зелено только 3-4 Мбай-а физической оперативной памяти Конечно, вьртуалькая память работает медленнее, чем физическая, но, во- первых, 100 Мбайт виртуальной памяти обойдутся вам неизмеримо дешевле- чем 100 Мбайт физической памяти, а во-вторых, процессоры 80386 и '80486 исполь- зуют специальные аппаратные средства ускоряющие работу подсистемы вирту- альной памяти. Кроме того, только механизм страничной виртуальной памяти может обеспе- чить прикладные программы относительно быстрой оперативной памятью, раз- мер которой больше размера физической памяти, установленной ь компьютере, Помимо страничной виртуальной памяти в процессорах i80386 и ,80486 реа- лизован так называемый режим виртуального процессора ,8086 или просто вир- туальный режим. Этот режим реализуется в рамках защищённого режима (про- цессор может переключиться в виртуальный режим только из защищённого ре- жима). В виртуальном режиме процессор способен выполнять прс-раммы, соста- вленные для процессора 18086, находясь в защищённом режиме и используя ап парлтные сре.’гтва защищённого режима мультизадачное!!», изолирование адрес- ных пространств отдельных задач друг ст друга, страничная виртуальная память. Наличие виртуального режима значительно облегчает проектирование опера- ционных систем, способных выполнять одновременно в мультизадачном режиме несколько программ, ориентированны-, ад oneрационную систему MS-DOS. Возможность одновременной работы нескольких программ, предназначенных для MS-DOS, реализована, например, в операционных системах WINDOWS версий 3.0 и 3.1 (в расширенном режиме и только при наличии процессоров i80386, 180486), OS/2 версии 2.0, Desk View 386 Перечислим кратко основные преимущества, которые получает программа, работающая в защищённом режиме процессора: возможность негосредс:венной адресации памяти за пределами первого мегабайта; для процесоров ,80386 и 180486 реализован механизм страничной гирту- альной памяти, позволяющий программам работать с памятью, размер которой может быть много больше физической оперативной памяти, уста- новленной в компьютере. аппаратная поддержка мультизадачное™ позволяет создавать на основе процессоров, работающих в защищённом режиме высокопроизводитель- ные мультизадачные и мультипользователъекие системы; эффектьная работа нескольким программ, составленных для MS-DOS, основанная на использовании виртуального режима работы процессора. Изучение защищённого режима мы начнём с описания метода адресации памяти, коренным образом отличающегося от привычного для вас метода <согмеит:смещеиие> реального режима. Однако вначале напомним, как адресует- ся память в реальном режиме. ’ДИАЛОГ-МИФИ" '
о Защищённый режим процессоров Intel 80286/80386/80486 Адресация памяти в реальном режиме Вы, наверное, знаете, что для работы с памятью используются две шьны - тина адреса и шина данных Физически память устроена таким образом, что во- можна адресация как 16-битовых слов, так и отдельных байтов памяти. Кроме ого, процессоры 180386 и >80486 могут адресовать 32-битовые слова памяти. В любом случае тах называемый физический адрес передаётся из процессора в амять по шине адреса. Ширина шины адреса определяет максимальный объём жзической памяти, непосредственно адресуемой процессе ром. На рис. 1 пока за- а схема взаимодействия процессора и памяти через тины адреса и данных Физический адрес Рис. /. Шина адреса и шина данных Например, компьютер IBM XT оснащён 20-разрядной шиной адреса и 16-раз- ядной шиной данных. Эк» означает, что имеется возможность адресоваться к 16 байтам памяти, т. е, к 1 Мбайту памяти Причём возможно адресоваться к айтам и словам размером в 16 бит. Так как адреса принято записывать в шестнадцатеричной форме, то мы можем аписать диапазон физических адресов для 20-разряднсй шины адреса следую- щим образом; I0000h <= [физический адрес] <= FFFFFh Таким образом, для представления шизического адреса в компьютерах ВМ PC и IBM XT используется двадцать двоичных или пять шестнадцатеричных азрядов. Однако все регистры процессора 18086 являются 16-р?зрядными Возникает :роблема представления 20-разрядного физического адреса памяти при помощи одержимого 16-разрядных регистров Для разрешения этой проблемы используется двухкомггонентный логический дрес. Логический адрес состоит из 16-разрядных компонент: компоненты сегме- та намята и компоненты смещения внутри сегмента. Для получения 20-разрядного физического адреса к сегментной компоненте риписы веется справа четыре нулевых бита шля расширения до 20 разрядов), атем полученное число складывается с компонентой смешения (рис. 2). Перед ложением к компоненте смещения слева дописывается четыре нулевых бита так же для расширения до 20 разрядов). Логический адрес принято записывать в форме <сегмент:смещение>.
Особенное™ защищенного режима процессора i80286 11 Рис. 2. Адресац -я памяти в реальном режиме Например, пусть у нас есть логичес- кий адрес 1234h:0123h- Сегментная ко- мпонента равна 1234h, компонента смешения - 0l23h Вычислим физичес- кий адрес, соответствующий нашему логическому адресу расширяем до 20 бит сегментную компоненту, дотисывая справа 4 кулевых бита, получаем число 1234l)h, расширяем до 20 бит компонен- ту смещения, дописывая слева 4 нулевых бита, получаем число 00123h; для получения физическою адреса складываем полученные числа: 1234(111+ 00123 h= 12453b Одному физическому адресу может соответствовать несколько логических. Например, физическому адресу 12453И соответствует логический 1245h:0003h. Фактически в схеме адресации памяти реального режима вся память как бы разбивается на сегменты Физический адрес начала сегмента (базовый адрес сег- мента) равен расширенной до 20 бит сегментной компоненте адреса (расширение выполняется дописыванием справа 4 нулевых бит). Сегменты могут начинаться только с физического адреса, который кратен 15 байтам. Поэтому он может начинаться только с границы параграфа. Компонента смещения при такой схеме адресации является смещением внутри сегмента памя- ти. А сам сегмент памяти задаётся сегментной компонентой (рис 3) Рис. 3. Соответствие логического адреса 0002h-'Wi2Sh физическом, адресу OOO^gh Логический адрес должен находиться в следующих пределах 3000h:0000?i <= (логический адрес! <= FFFFh 000FE ’ДИАЛОГ МИФИ'
2 Защищённый режим процессоров Intel 8028G/80386/80486 Здесь есть одна тонкость Логический адрес FFFFh:000Ffc соответствует макси- [ально возможному физическому адресу FFFFFh. Но, иссользуя 16-разрядные егистрь. процессора, вы можете задать и большее значение для логического ад- еса, например FFFFhOOlOb. Что Произойдёт в этом случае? Если в компьютере установлены процессоры i8086 или 18088, произойдёт пе- еполнение адреса. Оно будет проигнорировано процессором В результате лэги- ескому адресу FFFFh:OOIOh будет соответствовать физический адрес OOOOOh. Если же используются гроцессоры i80286, i80386 или i80486, физическая ши- и адреса шире 20 биг. Цля процессора i80286 шина адреса имеет ширину 24 би- а, а для процессоров i80386 и i8O48(> - 32 бита. При работе в реальном режиме «пользуются младшие 20 адресных линий - от АО до А19, остальные адресные инии аппаратура компьютера блокирует. Есть возможность снять блокировку с адресной линии А20 При этом в реаль- юм режиме появляется ещё один ’’льготный” сегмент памяти, лежащий выше раницы первого ме!абайта. Этот сегмент называется областью старшей памяти High Memory Area) Его диапазон логических адресов - от FFFFhOOlOh до fFFFh:FFFFh. Размер области старшей памяти 64 Кбайта без 16 байт Операционная система MS-DOS умеет использовать старшую область памяти, асполагая там своё ядро. Для этого необходимо подключить драйвер IIMEM SYS и поместить ь файл CONFIG.SYS строку >OS=HIGH Архитектура процессоров серии (80ХХХ, работающих в реальном режиме, [редполагает хранение сегментной компоненты адреса в сегментных регистрах: CS - сегмент кода; DS - сегмент данных; ES - дополнительный сегмент данных; SS - сегмент стека- ✓ Компонента смешения может находиться в регистрах ВХ. ЕР, SI, DI, IP. Задавая произвольные значения сегментной компоненты и компоненты сме- цения любая программа чожет адресоваться к любому участку памяти комлью- ера. В частности, любая программа может преднамеренно или из-за ошибки азрушить области данных, принадлежащие операционной системе Выделим два основных недостатка схемы адресации памяти реального режима: ограниченное адресное пространство (до 1 Мбайта и примерно 64 Кбайта старшей области памяти для процессоров i80286, i80386 и i80486); свободный доступ любых программ к любым областям данных, что предс- тавляет потенциальную опасность для целостности операционной системы. Этих недостатков полностью лишена схема адресации памяти, которая исполь- уется в защищённом режиме.
Особенности защищенного режима процессора i80286 13 Адресация памяти « защищённом режиме Основная тругность, с которой сталкивается программист, изучающий за- щищённый режим, - это сложная схема преобразования адресог. Поэтому мы уделим много внимания тому, как в этом режиме происходит адресация памяти. Для облегчения восприятия мы вначале опустим некоторые детали, отложив на время их полное описание. Преобразование адресов в защищённом режиме В защищённом режиме, так же как и в реальном, существуют понятия логиче- ского и физического адреса Логический адрес в защищённом режиме (иногда используется термин ’’гиртуалькый адрес") состоит из двух lb-разрядных ком- понент - селектора и смещения Селектор записывается в те же сегментные реги- стры, что и сегментный адрес в реальном режиме. Однако преобразование логи- ческого адрес?, в физический выполняется не простым сложением со сдвигом, а при помощи специальных таблиц преобразования адресов. В первом приближении можно считать, что для процессора i80286 селектор является индексом в таблице, содержащей базовые 24-разрядныс физические ад- реса сегментов. В процессе преобразования логического адреса в физический процессор прибавляет к базовому 24-разрядному адресу 16-разряднсе смещение, т. е. вторую компоненту логического адреса (рис. 4). Рис, 4. Упрощенная схема преобразования логического адреса а физический в защищённом режиме Такая схема формирования физического адреса позволяет непосредственно адресовать 16 Мбайт памяти с помощью 16-разрядчых компонент логического адреса. Заметьте, что селектор - это не сегментный адрес. Это индекс, с помощью ко- торого процессор извлекает из специальной таблицы 24-разрядный базовый ад рес сегмента В реальном режиме мы имеем дело с сегментным адресом и смеще- нием, а в защищённом - с селектором и смещением. На самом деле не все 16 бит селектора используются для индексации по таб- лице базовых адресов. В качестве индекса выступают старшие 13 бит. Два млад- "ДИМОГ-МИФИ"
14 Защищённый режим процессоров Intel 80296/90386/80486 ших бита (бит 0 и бит I) используются системой зашиты памяти, о чём мы под- робно поговорим в следующем разделе Бит 2 позволяет выбирать для преобра- зования адреса один из двух типов таблиц преобразования адресов. ’6 3 2 1 0 I—^1L1_L_LLI J 1Ш Индекс П RPL Рис. 5. Полный формат селектора адреса На рпс. 5 два младших бита обозначены как RPL (Requested Privilege Level). Это поле является запрошенным программой уровнем привилегий, и его мы бу- дем обсуждать позже. Поле TI (Table Indicator) состоит из ОДНО10 бита. Если этот бит равен нулю, для преобразования адреса используется так называемая глобальная таблица дескрипторов GDT (Global Descriptor Table), в противном случае - локальная таблица дескрипторов LDT (Local Descriptor Table). Таблица дескрипторов - это просто таблица преобразования адресов, содержа- щая базовые 24 разрядные физические адреса сегментов и некоторую другую информацию. То есть каждый элемент таблицы дескрипторов (дескриптор) соде- ржит 24-разрядный базовый адрес сегмента и другую информацию, описыва- ющую сегмент. Таблица GDT - единственная в системе. Обычно в ней находятся описания се- гментов операционной системы. Таблиц LDT может быть много Эти таблицы со- держат описания сегментов программ, работающих под управлением операцион- ной системы, т. е. отдельных задач. В каждый дачный момент времени процессор может использовать только одну таблицу LDT. Процессор имеет два регистра, предназначенных для адресации используемых в настоящий момент таблиц GDT и LDT. Регистр GDTR описывает расположе- ние и размер таблицы GDT а регистр LDTR содержит ссылку на использующу- юся в настоящее время таблицу LDT. На рис. 6 показана уточнённая схема преобразования адресов в защищённом режиме Из рисунка видно, что регистры процессора GDTR и LDTR определяют расположение в памяти таблиц соответственно GDT и LDT. Таблицы GDT и LDT содержат дескрипторы, описывающие сегменты памяти. В этих дескрипто- рах помимо другой информации (заштрихованная область) содержится 24-разря- дный базовый адрес сегмента. Старшие 13 битов селектора (индекс) выбирают элемент из таблицы GDT или LDT в зависимости от состояния бита Т1 селектора. Извлечённый из таблицы дескрипторов базовый адрес сегмента складывается процессором для получения 24-разрядного физического адреса (рис. 6). Селектор OOOOh адресует самый первый дескриптор в глобальной таблице дес крипторов GDT. Поле RPL для этого дескриптора равно 0, поле 1'1 также равно О Селектор 0008h указывает на второй элемент таблицы GDT, а селектор 0014h указывает на третий дескриптор в локальной таблице дескрипторов LDT, т. к. поле TI в нём равно 1.
Особенности защищенного режима процессора I80286 15 Рис. 0. Уточнённом схема нреобриаоааним адресов Детальнее описание схеме. преобразования адресов Теперь перейдём к более строгому описании схемы преобразования адресов в защищённом режиме. Регистр GDTR, ухазываюаий расположение в физической памяти и размер глобальной таблицы дескрипторов GDT, является ключевым ч схеме адресации защищённого режима. Формат регистр* GD7R Бааояый адрес GDT Йаамер GOT - 1 £4 бит» 1Й4$ит Рис. 7. Формат регистра GDTR процессора i80286 Регистр GDTR (рис. 7) имеет длину 5 байт. Старшие 3 байта содержат 24-раз- рядный физический адрес таблицы GDT, младыие 2 байта - длину таблицы GDT уменьшенную на 1 Длина GDT, уменьшенная на единицу, назььается пределом таблицы GOT (GDI limit). Она используется для проверки правильности задана емых программой селекторов. Лме индекса селектора должно .одержать ссылки только ка существующие элементы таблицы GDI, в противном случае произой- дет прерывание Зная размер GDT, процессор блокирует использование селекто- ров со значениями поля индекса, выходящими за рамки разрешённых. Аналогич- ный механизм используется и для проверки селекторов, ссылаютдихся на LDT. Перед переходом в защищённый режим прошамма должна создать в операти- вной памяти таблицу GDT и загрузить регистр GDTR при помощи специальной команды LGDT (синтаксис транслятора Turbo Assembler, режим [DEAL): Igdt [QWORD gdt_ptr] • Перед выдачей команды LODI gdt_ptr необходимо подготовить облапь памя- ти с адресом gdt_ptr, записав неё физический адрес таблицы GDT и её размер, уменьшенный на 1 (предел): » gdt_ptr dw GDT_LIMIT ; предел таблицы GDT base_l- dw ? ; младшее слово базового адреса GDT base_hi dw ? ; старшее слово базового адреса GDT •ДИАЛОГ-МИФИ
16 Защищённый режим процессоров Intel 80286/80386/80486 Несмотря на то что размер регистра GDTR составляет 5 байт, в качестве опе- ранда для команды LGDT используется адрес области памяти размером 6 байт. Здесь нет ошибки, процессор i80286 использует только 5 байт из этой области, т. к. физический адрес содержит 24 разряда. Процессоры i80386 и 180486 в 32- разрядном режиме используют все 6 байтов, загружая в 6-байтный регистр GDTR 32-битовый физический адрес таблицы GDT и её 16-битовый предел. Сначала мы познакомим вас со структурой таблицы GDT (и соответственно с идентичной ей структурой таблицы LDT), а затем на примере фрагмента прог- раммы покажем, как создать таблицу GDT и загрузить регистр GDTR. • Как мы ухе говорили, таблицы GDT и LDT представляют собой массивы дес- крипторов - описателей сегментов (рис. 8). Кроме дескрипторов, описывающих сегменты памяти, таблица GDT может содержать специальные типы дескрипто- ров - вентили вызова (call gate), задач (task gate) и ловушек (trap gate). Вентили определяют точки входа в соответствующие процедуры. Вентиль вы- зова задает адрес подпрограммы, вызываемой, например, по команде CALL. При вызове подпрограммы через вентиль в качестве операнда для CALL используется - селектор, адресующий соответствующий дескриптор в таблице GDT или LDT. Резерв Доступ I Базовый адрес | Предел 1© бит 8 бит I мд“т* —J 1© бит ’ Рис. 8. Дескриптор сегмента для процессора i80286 Длина дескриптора составляет 8 байт. Он состоит из следующих полей: базового адреса длиной 24 бита, содержит физический адрес сегмента, описываемого данным дескриптором; предела содержит размер сегмента в байтах, уменьшенный на единицу; доступа описывает тип сегмента (сегмент кода, сегмент данных и др.); зарезервированное поле длиной 16 бит для процессора i80286, должно со- держать нули, оно используется процессорами i80386 и 180486 (там, в час- тности, хранится старший байт 32-разрядного базового адреса сегмента). В реальном режиме начало сегмента в памяти определяется сегментным адре- сом, длина сегмента составляет 64 Кбайта. В защищённом режиме можно зада- вать сегменты меньшего размера (процессоры i80386 и 180486 допускают такдо существование сегментов с размером, значительно превышающим 64 Кбайта). При этом процессор автоматически отслеживает попытки программы обратиться за пределы сегмента, заданные в дескрипторе. При обнаружении такой попытки выполнение программы прерывается. Ограничение размера сегментов и контроль за попытками адресации памяти вне пределов сегментов сильно повышает надёжность системы. Программа не мо- жет разрушить чужие сегменты, в частности сегменты операционной системы. Подробнее о защите мы расскажем в следующем разделе.
Особенности защищенного режима процессора i80286 17. п crl и Поле доступа сегмента кода 7 в а 4 з 2 1 О И [ои. j’i°l DH А | Поле доступа сегмента данных 7 6 5 4 3 2 1 О Гр I C*>L 10 I TYPE 1 Поле доступа системного сегмвнгд 7 6 5 4 3 2 1 О Рис. 9. Форматы паля доступа дескриптора Поле доступа, занимающее в дескрипторе один байт (байт доступа), служит для классификации дескрипторов (рис. 9). Поле доступа дескриптора сегментов кода содержит битовое поле R, называе- мое битом разрешения чтения сегмента. Если этот бит установлен в 1, программа может считывать содержимое сегмента кода. В противном случае процессор мо- жет только выполнять этот код. Программа не может модифицировать сегмент кода. Это означает невозмож- ность создания самомодифицирующихся программ для защищённого режима (распространённая, но порочная практика среди программистов, создающих про- граммы для MS-DOS). Впрочем, есть обходной путь. Для сегмента кода можно создать ещё один, алиасный дескриптор, в котором этот сегмент отмечен как сег- мент данных. Если для этого сегмента будет разрешена запись, ничто, кроме здравого смысла, не помешает вам модифицировать код программы во время её выполнения. Бит С называется битом подчинения, он будет рассмотрен в следу- ющем разделе. Биты Р и А предназначены для организации виртуальной памяти. Их назначе- ние будет описано в разделе, посвящённом виртуальной памяти. Сейчас отметим, что бит Р называется битом присутствия сегмента в памяти. Для тех сегментов, которые находятся в физической памяти (мы будем иметь дело в основном с та- кими сегментами), этот бит должен быть установлен в 1. Любая попытка прог- раммы обратиться к сегменту памяти, в дескрипторе которого бит Р установлен в О, приведёт к прерыванию. Бит А называется битом обращения к сегменту и для всех наших программ до- лжен быть установлен в О. Поле доступа дескриптора сегмента данных имеет битовые поля, W и D. Поле W называется битом разрешения записи в сегмент.. Если этот бит установлен в 1, наряду с чтением возможна и запись в данный сегмент. В противном случае при попытке чтения выполнение программы будет прервано. Поле D задаёт направление расширения сегмента. Обычный сегмент данных расширяется в область старших адресов (расширение вверх). Если же в сегменте расположен стек, расширение происходит в обратном направлении - в область младших адресов (расширение вниз). Для сегментов, в которых организуются стеки, необходимо устанавливать поле D равным 1. Дескрипторы системных сегментов содержат поле TYPE, определяющее тип системного сегмента. В табл. 1 приведены возможные для этого поля значения. ’диалог-мифи'
18 Защищенный режим процессоров Intel 80286/80386/80486 Таблица 1. Тилы системных сегментов Пале ТУРЕ Тип сегмента 0 Запрещённое значение 1 Доступный TSS для процессора i80286 2 Сегмент LDT 3 Занятый TSS для процессора i80286 4 Вентиль вызова для процессора i80286 5 Вентиль задачи для процессоров i80286 и i80386 6 Вентиль прерывания для процессора i80286 7 Вентиль исключения для процессора i80286 8 Запрещённое значение 9 Доступный TSS для процессора i80386 А Зарезервировано В Занятый TSS для процессора i80386 С Вентиль вызова для профессора i80386 D Зарезервировано Е Вентиль прерывания для процессора i80386 F Вентиль ловушки для процессора i80386 Мы на время отложим детальное описание всех типов системных дескрипто- ров, так же как и поля DPL, использующегося для организации защиты сегмен- тов, для того чтобы сконцентрировать своё внимание на схеме преобразования адресов в процессоре i80286. Итак, перед переводом процессора в защищённый режим нам необходимо сформировать в памяти таблицу GDT и загрузить в регистр GTDR её адрес и предел при помощи команды LGDT. В терминах языка ассемблера структура дескриптора может быть описана сле- дующим образом: ' STRUC desc_struc limit dw 0 ; предел сегмента base_lo dw 0 ; младшее слово 24-битового base_hi db 0 ; физического адреса сегмента старший байт 24-битовоГр access db и ; физического адреса сегмента поле доступа reserved dw 0 , зарезервировано, для сегментов ENDS dese_strue » » процессора i80286 должно быть равно нулю Тогда мы можем определить таблицу GDT как набор дескрипторов со струк- турой desc_struc: jDT_BEG - $ ; отмечаем начало GDT Label gdtadr word
Особенности защищенного режима процессора I80286 19 gdt_0 desc_struc <0,0,0,0,0> ; первый элемент . не используется gdt_gdt desc_struc <GDT_SIZE-1 ..,DATA_ACC, 0> gdt_ds desc_struc <DSEG_SIZE-1 ,,,DATA_ACC,0> gdt.cs desc_struc <CSEG SIZE-1 ,,.CODE_ACC 0> gdt-SS desc_struc <STACK_SIZE-1.,,DATA_ACC,0> GDT_SIZE = ($ - GDT_BEG) ; вычисляем размер GDT В этом примере самый первый дескриптор инипиалигкруется нулями. Так де- лается всегда. Самый первый дескриптор в таблицах GET и LET никогда не ис- пользуется. Программа может загрузить в сегментный регистр селектор, сэответ- стъующий первому дескриптору (поле индекса в таком селекторе равно нулю}, одяако при попытке использовать такой селектор произойдёт прерывание работы пр ограм мы. Селектор с нулевым полем индекса (пустой селектор' загр. жаетгг операциоююй системой в неинициализированные сегментные регистры перед пе- редачей управления запущенной программе. Второй дескриптор описывает саму таблиту GDT, в поле предела cioht значе- ние GDT_SIZE-1. Э’о предел таблицы GDT В поле доступа ггоит значение, со- ответствующее сегменту данных. Следующие три дескриптора тписьвают сегмен~ы, адоесусмые регистрами со- ответственно os, cs и ss (сегменты данный, кода и стека). В них заполнены поля предела и.доступа. Сни могут быть определены, например, следующим образом: CODE_ACC ecu 10011000b DATA_ACC equ 1001000011 В нашем примере мы заполнили не все поля дескрипторов в таблице GDT Остались незаполненными поля oasejo и base_hi, т. е. физический адрес сегмен- та данных. Физический адрес сегмента данных должен быть вычислен в реальном режиме на основании значений се-ментнсго адреса и смещения т. е. на основании двух компонент логического адреса реального режима. Можно предложить следую- щую процедуру для вычислен “ч физического адреса (на примере вычисление физического адреса таблицы GDT) и записи вычисленного адреса в дескриптор; ; Загружаем в ах адрес се-мента данных DGROUP mov ах,DGROUP , Формируем в dl ах физический адрес, соответствующий ; сегментному адресу DGRCUP mov d1,ah shr dl,4 sill ax, 4 ; Складываем со смещением add ax,OFFSET gdtadr adc dl,0 ; Записываем физический адрес GDT в элемент GDT ; описывающий саму GDT mev bx,OFFSET gdt gdt mov [(desc_struc bx).baee_l] ax mov [<desc_struc bx).base_h],dl •диалог-мили-
20 Защищённый ражим процессоров Intel 80286/80386/80486 Аналогично заполняются и другие элементы таблицы GDT. 1 Так как дескриптор С адресом gdt_gdt описывает саму таблицу GDT (и формат | этого дескриптора подходит для команды LGDT), его можно использовать для 1 загрузки регистра GDTR: J Igdt (QWORD gdt_gdt] ,И Если вы создаёте программу на языке Си, глобальная таблица дескрипторов ,1 GDT может быть определена с помощью типа descriptor следующим образом: | descriptor gdt[5]; В этом примере создаётся таблица GDT, содержащая пять дескрипторов. Тип 4 descriptor определяется так: ? typedef struct descriptor { word limit; 1 word base_lo; > •! unsigned char base_hi; | unsigned char access; 2 unsigned reserved; } descriptor; i| Инициализацию дескрипторов в таблице GDT можно выполнить, например, с 1 помощью следующей функции: void init grit descriptorC descriptor *descr, // указатель // на инициализируемый дескриптор i unsigned long base, // базовый адрес сегмента word limit, // предел сегмента tj unsigned char acc_byte) // поле доступа descr->base_lo = (word)base; descr->base_hi = (unsigned char)(base >> 16); descr->access = acc_byte; descr->limit - limit; • J descr->reserved = 0; J ) ' I 93 Приведём пример использования этой функции для записи в третий по счёту •Я элемент GDT информации о сегменте данных с сегментным адресом _DS и пре- 1 делом Oxffff: 1 init_gdt_descriptor(&gdt[2], MK_LIN_ADDR(_DS, 0), 0xffffL, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); 1 Преобразовать логический адрес реального режима (сегментхмещение) в фи- | зический адрес можно с помощью следующей макрокоманды: #define MK_LIN_ADDR(seg,off) j (((unsigned long)(seg)) << 4) + (word)(off) Для формирования поля доступа в нашем примере используются такие опре- ’S деления: tfdefine TYPE_CODE_DESCR 0x18 1 #define TYPE_DATA_DESCR 0x10 tfdefine SEG_WRITABLE 0x02
Особенности защищенного режима процессора I80286 21 ^define 3E3_READABLE 0x0?. #define SEG_PRESENT_BIT 0x80 К сожалению: встроенные з Borland С 3.0 Inline-ассемблер не позволяет ис- пользовать команду LGOT в программе, составленной на языке Си. Аналогичное (лракиченис имеется и ь Microsoft Quick С. Поэтому для загрузки этого и неко- торых других регистров приходится использовать отдельные модули, составлен- ные полностью на я?ыке ассембле ра. В отличие от регистра GDTJ, регистр LDTR имеет только 16 разрядов. Он со- держит не адрес и размер таблицы LDT, а селектор дескриптора, описывающего таблицу LDT Это системный дескриптор, который должен находиться в таблице GDT и иметь в ноле TYPE значение 2. Дескриптор сегмента LDT содержит базовый адрес и предел таблицы LDT. Мы уже говорили, что простейшие системы защищённого режима могут не ис- пользовать таблицу LDT вовсе. Все приведённые в этой книге примеры прог- рамм пользуются только GDT. Практическая польза от применения таблиц LDT появляется только в мультизадачных системах. В этом случае назначение каждой задаче собственной LDT позволяет полностью изолировать адресные пространст- ва отдельных задач. Но об этом мы будем говорить в разделе книги, пос- вящённом мультизадачное™ Подведём итоги - Вы узнали, что в защищённом режиме применена новая схема преобразо- вания логического адреса ь физический, сильно отличающаяся от исполь- зуемой в реальном режиме. Эта схема даёт, в частности, возможность ад- ресовать непосредственчо до 16 Мбайт физической памяти Для преобразования адреса процессор i80286 использует таблицы дескри- пторе в, в которых хранятся базовые адреса сегментов, размеры сегментов и другая Информация. Одновременно процессор может использовать две таблицы дескрипторов - • локальную (LDT) и глобальную (GDT). Используемая таблица определя- ется полем Т1 селектора Расположение и размер таблицы GDT должны быть загружены в -.пеци- альный регистр процессора - GDTR Это можно сделать командой LGDT. В таблице GDT могут находиться дескрипторы сегментов кода, данных, системные дескрипторы Например, там может быть дескриптор, описыва- ющий таблицу локальных дескрипторов LDT (если она используется). Перед переключением в защищённый режим программа должна подгото- вить таблицу GDT и загрузить её адрес в регистр GDTR. Защита в процессоре i80286 Мы уже говорили, что операционная система MS-DOS, использующая реаль- ный режим работы процессора ке защищена от прикладных программ. Подсис- тема управления памятью MS-DOS основана па разбиении всей памяти на участ- ки, в начале которых помещаются блоки управления памятью МСВ (Memory ДИАЛОГ МИФИ'
22 Защищённый режим процессоров Intel 80286/80386/80486 Control Block). При запуске программы MS-DOS выделяет ей необходимое коли- чество блоков и загружает соответствующим образом сегментные регистры. Если программа не изменяет содержимое сегментных регистров, она работает только с теми сегментами памяти, которые выделены ей операционной системой. Однако ничто не мешает любой программе загрузить в сегментные регистры лю- бое значение, в том числе адреса сегментов самой операционной системы. Поэтому, строго говоря, MS-DOS не имеет сколько-нибудь надёжного механи- зма управления памятью - всё основано на выполнении программами ’’джентель- менского соглашения” о неразрушении операционной системы. Для повышения надёжности работы всей системы в целом необходимо запре- тить обычным пользовательским программам модифицировать области памяти, принадлежащие операционной системе. Если система работает одновременно с несколькими пользователями (мультипользовательская операционная система), необходимо также закрыть программам доступ к памяти, распределённой другим пользователям. Иначе говоря, нужно отделить адресное пространства операцион- ной системы от адоесного пространства пользовательских программ, с одной сто- роны, и адресные пространства отдельных пользователей друг от друга, с другой стороны. Такие операционные системы, как WINDOWS и OS/2, являются однопользо- вательскими, но многозадачными системами. Пользователь может запустить од- новременно несколько программ. В этом случае было бы желательно разделить адресные пространства этих программ с целью исключения их влияния друг на друга (и, разумеется, на операционную систему). Аварийное завершение одной запущенной задачи не должно вызывать аварийного завершения остальных задач или, тем более, всей операционной системы. Кроме того, необходимо разрешить модулям операционной системы доступ к памяти всех запущенных программ для выполнения эффективного управления работой всей системы. Отсюда, с одной стороны, вытекает идея наделения программ операционной системы некоторыми привилегиями по сравнению с пользовательскими програм- мами, с другой стороны - идея наделения отдельных участков памяти средствами защиты от доступа к ним со стороны непривилегированных программ. Многие большие и мини-ЭВМ реализуют схему "супервизор-пользователь”. Операционная система работает1 в режиме "супервизор”, и ей доступны все ресу- рсы компьютера - вся память, команды процессора и т. д. Запущенные програм- мы работают в режиме "пользователь” и имеют доступ только к тем участкам памяти, которые выделены им операционной системой. Кроме того,«они ограни- чены в использовании .некоторых команд процессора (команд ввода/вывода). Для предотвращения доступа программам, работающим в режиме "пользова- тель", к чужим блокам памяти используются так называемые "ключи” (это про- сто целые числа). Отдельным блокам памяти операционная система назначает свои "ключи”. Кроме того, запущенные программы также снабжаются "ключа- ми”. Программа может иметь доступ только к таким блокам памяти, к которым подходит "ключ”, имеющийся в распоряжении программы.
Особенности защищенного режима процессора i80286 2» . Такая схема не обеспечивает полного изолирования адресных пространств от- дельных задач. Адресное пространство здесь одно, но для обычных программ ра- зрешен доступ только к своему участку памяти в соответствии с имеющимся "ключом”. Однако в системе может работать несколько программ с одинаковым "ключом" -памяти! Кольца защиты Процессор i80286 использует более гибкую и надёжную схему защиты опера- ционной системы и программ друг от друга. В Этой схеме используются привилегии четырёх уровней - от 0 до 3. Самые большие привилегий соответствуют уровню 0. Обычно такими привилегиями об- ладает Ядро операционной системы. Минимальные привилегии у пользователь- ских программ - уровень 3. Уровни привилегий часто называют кольцами защиты (рис. 10). Как распределить привилегии программ в операцион- Рис. J0. Кольца защиты ной системе? Можно использовать, например, такое ра- спределение: Кольцо 0 - ядро операционной системы, систем- ные драйверы. Кольцо 1 - программы обслуживания аппарату- ры, драйверы, программы, работающие с портами ввода/вывода компьютера. Кольцо 2 - системы управления базами данных, расширения операционной системы. Кольцо 3 • прикладные программы, запускаемые пользователем. Несложные системы могут использовать не все кольца, а только некоторые или даже одно. Например, можно расположить все программы операционной си- стемы в кольце 0, а пользовательские программы - в кольце 3. Это вариант опи- санной выше схемы "супервизор-пользователь”. Простейшие системы можно полностью реализовать в нулевом кольце. Имен- ' но так мы и сделали в примерах программ, приведённых в этой книге. Как практически используются кольца защиты? Вспомним, что любой селектор имеет-поле RPL (биты 0 и 1). В регистре CS хранится селектор текущего выполняемого сегмента кода. Этому селектору соот- ветствует дескриптор в таблице GDT или LDT. В дескрипторе, в байте доступа, располагается поле DPL (биты 5 и 6). Указанные поля участвуют; в механизме защиты памяти. Когда операционная система подготавливает программу для запуска, она фор- мирует в GDT или LDT дескриптор, описывающий сегмент кода программы. В этом дескрипторе в поле DPL байта доступа проставляется номер кольца, в ко- тором будет работать данная программа, - текущий уровень привилегий CPL (Current Privilege Level). То есть возможности программы определяются содер- жимым ноля DPL в байте доступа. •ДИАЛОГ-МИФИ'
24 Защищённый режим процессоров Intel 80286/80386/80486 Текущий уровень привилегий копируется в поле RPL - лектора сегмента ко- ‘ да, загруженного в регистре CS. Программа всегда можи проанализировать свой - текущий уровень привилегий, исходя из значения поле RPL в регистре CS. Од- у нако она не может изменить свой уровень привилегий простой заменой содержи- мого поля RPL в сегменте CS. Итак, программа получает от операционной системы текущий уровень приви- легий CPL, который она может проанализировать на основании содержимого ре- ; гистра CS. Дескрипторы, описывающие сегменты данных, содержат поле уровни лривиле- . гий дескриптора DPl iDescriptor Privilege Level). Иоле DPL содержит минимвль* -: ныс привилегии, которые нужны для доступа к сегменту данных. Перед тем, как обратиться к сегменту дачных, программа должна загрузить в один из сегментных регистров селектор, соответству-иций нужному лгменту данных. К селектор-* необходимо указать поле уровня опрашиваемых т.рквиле- у гий RPL (Requested Privilege Level) у Программе будет предоставлен доступ к сегменту тслько в том случае, когда уровень привилегий дескриптора запрашиваемого сегмента DPL больше или ра- ' вен значению tnax(CPL,RPL), т. е. на «большему из значений текущего уровня привилегий CPL и уревня запрашиваемых привилегий RPL: ; DPL >= max(CPL.RPL) : Если программа попытается получить доступ к более привилегированному, ' чем ока сама, сегменту памяти, её выполнение будет прервано. . - Б наших примерах реализованных для простоты в кольце 0, все уровни при- J вилегий равны О, т. е DPL “ CPL « RPL °- 0. Тип сегментов • V Поле TYPE дескриптора определяет способ, которым можно использовать тот или иней сегмент. Разделение сегментов на типы позволяет защититься от слу- чайного или преднамеренного использования сегментов не по назначению. Сегмент кода может быть закрыт для пения устанэвк-С бита R в байтс. досту- па. Такие сегменты можно только выполнять, но нельзя читать. В сегмент кода нельзя записывать какие-либо данные. В регистп CS можно загружать только та-, : кие селекторы, которые относятся к сегментам кода. Сегменты данных могут быть закрыты для записи установкой бита W в байте4’ - досг. та Сегменту данных нельзя передать управление загрузив его селектор в регистр CS Дескрипторы некоторых типов, например описывающих расположение табля- ;< цы ШТ иль сепигчтз с-хлочния задачи,-о к< лором ыь будем п>а»>ри~ь п-1зжс, _> нельзя использовать для чтения или записи, даже если программа выполняется в нулевом приоритетном вальце. В случае такой необходимости следует создать п', допоейтгельные (алиьскые) дескрипторы, в которых эти же сегменты писаны как сепеситы данчы*.. •'
Особенности защищенного режима процессора I80286 25 Гранины сегментов Программы рильного режима работают 1сегда с сегментами размером 64 Кбайте Если программа состоит из иесколькю сегментов, то еекоторые сег- менты могут перекрываться Существует потенциальная опасность, что в резуль- тате программной ошибки (например, выхода индекса массива за допустимые пределы) произойдёт запись в другой сегмент Процессор i80286 позволяй- создавать сегменты любого размера в предела* 64 Кбайт (процессоры i80386 и >80486 могут работать с сегментами размерен 4 Гбайта). Креме того, он следит за тем, чтобы три адресации тгмятя не проис- ходил выход за границы сегмента. । ракпцы сегмента задаются полем предела > дескрипторе сегмента. Мы уже говорили, что значение этого поля должно быть равно размеру сетмента в байтах Ь.ГИУС ЙЦИНИ-t Интерпретация поля пределг. ззгисит от состояния бита D поля доступа .Для сегментов стеков необходимо устанавливать поле D равным 1. В этом случае по- пытка записи к переполненный стек вызовет прерывание программы. В ответ на это прерывание операционная система может, например, выделитс» дополнитель- ную память цля стс» а. В реальном режиме^ перегспнение стека никак не контролируется и может привести к разрушению сам е й программы или операционной системы. Привилегированные и чувствительные команды Для обеспечения надёжности работы операционной системы необходимо огра- ничить использование обычными программами некоторых команд процессора. Например, обычные программа. не должны иметь доступа к командам загрузка системных регистров GDTR и LDTR. В табл. 2 приведён список привилегированных команд, которые могут выпол мяться только в нулевом приоритетном кольце, т. е. только теми программами, которые имеют наибольшие привилегии (CPL - 0). Таблица 2. Г •. ^легированные команды процескор л i80286 команда Выполняемая функция Lgdt LLDT \ UDT LTR LMSW CLTS HLT Загрузка регистра глобальной таблицы дескрипторов GDTR Загрузка регистра локальной таблицы дескрипторов LDTR Загрузка регистра таблицы дескрипторов прерываний IDTR Загрузка регистра задачи TR Загрузка слова состояния машины MSW Сброс флага переключения задачи Останов процессора -диалог-мифи
26 Защищённый режим процессоров Intel 80286/8038$/80486 В этой таблице вам знакомы только команды LGDT .и LLDT, остальные кома- нды мы разберём по мере изучения различных возможностей процессора i80286, ' таких, как обработка прерываний в защищённом режиме и мультизадачиость. •. ! Существуют команды, которые должны не только выполняться • нулевом кольце, но использование которых должно быть запрещен^лдля:программ, имею- * щих уровень привилегий ниже некоторого уровня, заданного дЛя всей системы в , целом. Кроме того, функции некоторых команд было 'былкелательно модифици- ровать в соответствии с привилегиями выполняющей их программы. Такие кома- , нды называются чувствительными. ? Кроме привилегированных команд, необходимо ограничить обычные програы- ; мы в использовании команд ввода/вывода: IN, OUT, INS, OUTS. С помощью . этих команд программа может, например, перепрограммировать контроллеры прерываний и прямого доступа к памяти, что. в свою очередь, откроет путь к не- ( посредственной модификации памяти по физическим адресам. ,< , i Также не следует разрешать обычным программам использовать команды, ко-, торые могут заблокировать прерывания: CLI, STI, LOCK В мультизадачной сре-.',, де обычные программы не должны иметь возможность отключать механизм разг ’ | ’ деления времени между задачами. , ;> Регистр FLAGS флагов процессора i80286 в разрядах 12 - 13 содержит двух- ? битовое поле IOPL (Input/Output Privilege Level). Оно определяет наименее при- вилегированное кольцо, в котором разрешено использовать команды ввода/вы- ' вода. Программы, работающие не в нулевом кольце, не могут сами модифицировать <3 поле IOPL регистра FLAGS. При выполнении команд, загружающих регистр флажков (IRET и POPF) не в нулевом кольце, поле IOPL не модифицируется. j Аналогично без изменения остаётся флаг разрешения прерываний IF. ( Межсегментная передача, управления " В реальном режиме передача управлении выполняется с помощью команд IMP, CalL, IN1‘, RET, IRET, а также при возникновении прерываний. Внугри- сегментная передача управления выполняется командами JMP, CALL, RET, Д." межсегментная Передача управления - командами JMP, CALL, INT, RET, IRET#, в случае возникновения прерываний. В защищённом режиме всё аналогично. При внутрисегментной передаче угра- вления в регистр 1Р заносится новое значение, а регистр CS не модифицируется^ При межсегментной передаче одновременно изменяются регистры CS и IP, а та кже иногда и регистр флагов FLAGS (прерывания и комашы RET, IRET). Операпнонйая система MS-DOS, работающая в реальном режиме, позволяет любой программе вызывать любые подпрограммы. Единственное условие для ус- пепгного вызова подпрограммы - знание адреса подпрограммы (сегмента и cw-!i щения) и формата передаваемых регистров. При проектировании защищённых систем необходимо предотвратить возмож- ность непосредственного вызова произвольных привилегированных подпрограмм i
Особенности защищенного режима процессора i80286 27 менее привилегированными. А также необходимо обеспечить существование ме- ханизма вызова непривилегированной программой модулей операционной систе- мы (привилегированных) для получения обслуживания. Например, чтобы узнать текущее время ити обратиться к. магнитному диску непривилегированная прог- рамма должна вызвать соответствующие модули операционной системы. Процессор i80286 содержит все средства, необходимые для организации, с од- ной стороны, защиты модулей операционной системы от несанкционированного вызова прикладными программами и, с другой стороны, для обслуживания моду- лями операционной системы вызовов прикладных программ. Команды CALL u JMP При использовании команд CALL или JMP для внутрисегментной передачи управления в качестве операнда дня команд необходимо указывать смешение модуля в текущем сегменте, которому будет передано управление. При передаче управления процессор проверяет смещение на предмет выхода за пределы теку- щего сегмента кода. В случае использования этих команд для межсегментной пе- редачи управления существуют две возможности. Во-первых, программист может указать в качестве операнда селектор дескрип- тора вызываемого сегмента кода. Во-вторых, программист может указать в качестве операнда селектор, которо- му соответствует дескриптор специального типа - вентиль вызова. Вентиль вызо- ва содержит логический (а не физический, как дескриптор сегмента) адрес вызы- ваемого модуля. Первый способ называется прямым вызовом, второй - вызовом через вентиль вызова. Рассмотрим сначала прямой вызов сегмента. В этом случае операнд команды вызова - селектор дескриптора вызываемого или, другими словами, целевого сегмента. На выполнение прямого вызова целе- вого сегмента или прямого перехода к целевому сегменту влияет бит подчинения С, который располагается в бите 2 байта доступа дескриптора целевого сегмента. Если бит С установлен в 0, целевой сегмент называется несогласованным. Не- согласованный сегмент может быть вызван только такой программой, которая имеет большие или такие же привилегии, что и целевой сегмент. Го есть должно выполняться условие CPL <» DPL. Обычная программа, выполняющаяся в кольце 3, не может вызывать несогла- сованный сегмент (или передавать управление несогласованному сегменту), на- ходящемуся в кольцах 0, 1 или 2 Этот механизм блокирует несапкционирован ный вызов модулей операционной системы программами пользователя. Однако должен существовать способ безопасного вызова модулей операцион- ной системы в заранее оговорённых точках для того, чтобы программы могли получать обслуживание от привилегированных модулей ядра операционной сис- темы. Прямой вызов несогласованного сегмента здесь не подходит, т. к. ядро ра- сполагается в нулевом кольце. ’ДИАЛОГ-МИФИ’
28 Защищённый режим процессоров Intel 80286/80386/80486 Если программный сегмент, располагающийся в ядре операционной системы, я должен вызываться как самой операционной системой в нулевом кольце, так и! программами пользователя в менее привилегированных кольцах, можно приме-] нить согласованный сегмент. В согласованном сегменте кода бит подчинения С 1 байта доступа установлен в 1. Согласованный сегмент можно вызывать из прог-;! рамм, находящихся в любом кольце. Ио в любом случае при вызове этот сег-1 мент будет выполняться с привилегиями вызывающей программы. Если соглас.о- I ванный сегмент вызывается из кольца 0, он будет выполняться с уровнем приви ’ легий 0, если из кольца 3 - с уровнем привилегий 3. ?s Другой способ выполнить межсегментную передачу управления - использо-а вать передачу управления через вентиль вызова. В этом случае команды CALL,] или JMP адресуются к дескриптору с типом вентиля вызова (рис. 11) Пол* доступа вентиля аазоаа |р | ОРТ | О | О | 1 | о | о | 7 е а 4 3 2 1 а Рис. II. Дескриптор вентиля вызова . Селектор и смещение представляют собой адрес вызова или передачи управ-1 ления в целевом сегменте. Поле счётчика слов используется при передаче пара-]; метров вызываемому модулю. ' j Поле DPL вентиля вызова указывает минимальный уровень привилегий, необ*^ ходимый для получения доступа через данный вентиль. Операционная системам может подготовить для программ пользователя вентили, доступные из кольца 3 л обеспечивающие вызов процедур обслуживания, располагающихся в ядре опера-4 ционной системы в кольце 0. Однако программы 3 кольца смО1ут обращаться только к таким вентилям вызова, которые содержат в поле DPL значение 3. Прж этом управление через вентиль вызова передаётся только в ту точку, которая описана в данном вентиле и является безопасной с точки зрения операционной системы. Программа пользователя не сможет передать управление в середину] модуля или в середину машинной команды, 1 Но есть ещё проблема с передачей параметров. Обычно передача параметром выполняется через стек. Но для обеспечения зашиты программы нулевого колы] ца используют отдельный стек (вообще говоря, для каждого кольца используется отдельный стек, механизм переключения стеков мы рассмотрим при описаний мультизадачности). 1 При вызове сегмента через вентиль вызова процессор копирует'из стека вы . зыкающей программы в стек целевого сегмента такое количество 16-6итовызй слов, которое указано в поле 5-разрядного счётчика слов вентиля вызова Таки способом вызываемому модулю можно передать до 31 параметра. |
Особенности защищенного режима процессора i80286 29 Вентиль вызова - идеальное средство для предоставления обычным програм- мам сервиса со стороны операционной системы. С одной стороны, вентиль вызо- ва, формируемый операционной системой, позволяет непривилегированным про- граммам передавать управление привилегированным кодовым сегментам для по- лученья необходимого обслуживания. С другой стороны, операционная система имеет возможность держать под своим контролем использование вентилей вызо- ва, задавая в поле DPL вентиля минимальный уровень привилегий, которыми должна обладать прмрамма, передающая управление через этот вентиль, а так- же безопасный адрес входа в целевом сегменте. Команды R£.T u IRET Команды RET и IRET предназначены соответственно для возврата из подпро- грамм и процедур обработки прерываний. Команда RET может возвращать управление в пределах одного сегмента (вну- трисегментная форма) или в другой сегмент (межсегментная форма). При выполнении внутрисегментной формы команды RET процессор выполня- ет проверку превышения границы текущего сегмента, не позволяя передавать управление за его пределы. Когда выполняется межсегментная команда RET или команда IRET, процес- сор проверяет привилегии селектора сегмента программы, выбираемого из стека (т. е. селектора сегмента, которому будет передано управление при выполнении команд RET или IRET). Процессор может выполнить возврат только в менее привилегированный сегмент или в сегмент, обладающий такими же привилегия- ми, что и тот, из которого выполняется возврат. Виртуальная память в процессоре i80286 Процессор i80286 может непосредственно адресовать до 16 Мбайт физической памяти, однако реально компьютеры редко имеют оперативную память такого размера. Обычный размер оперативной памяти для IBM АТ составляет 2- 4 Мбайта (здесь имеется в виду расширенная память - Extended Memory). Механизм виртуальной памяти, реализованный в процессоре i80286, позволя- ет организовать память большого размера (например, 16 Мбайт) с использовани- ем относительно небольшой физической оперативной и дисковой памяти Основная идея виртуальной памяти в том, чтобы хранить (и обновлять) содер- жимое большой виртуальной памяти на диске, ’’подкачивая” отдельные участки виртуальной памяти в реальную оперативную память по необходимости. Можно, например, хранить все используемые программой сегменты на диске, а п физиче- скую память записывать только те сегменты, которые необходимы для выполне- ния программы в настоящий момент. Процесс ’’подкачки” сегментов с диска в память и их выгрузки после изменения на диск называется свопингом Операционная система должна вести учёт сегментов и знать, какие сегменты находятся в памяти, а какие - на диске. Процессор i80286 может оказать ей в этом существенную помощь. Последние два поля дескриптора, которые мы ещё ‘ДИАЛОГ-МИФИ’
30 Защищённый режим процессоров Intel 80286/80386/80486 не рассматривали - бит присутствия сегмента в памяти Р и бит обращения к сег- менту памяти А, предназначены для аппаратной реализации учёта сегментов. Бит Р должен быть установлен в 1 для тех сегментов, которые Находятся в физической памяти. Сегменты, временно отсутствующие в памяти и находящие- ся на диске, помечаются в дескрипторе битом Р, сброшенным в О'. Установкой и сбросом бита Р занимается операционная система. А вот провер- ка этого бита - работа для процессора. Когда программа обращается к отсутству- ющему в физической памяти сегменту (загрузкой селектора в сегментный ре- гистр), выполнение программы прерывается и управление передаётся операцион- ной системе. Та, в свою очередь, "подкачивает" нужный сегмент в оперативную память и устанавливает для него бит Р в 1, после чего работа программы возоб- новляется. Время от времени операционная система должна находить сегменты, к кото- рым было обращение, и в случае их изменения сбрасывать на диск. Кроме того, если для "закачки” нового сегмента в физической памяти недостаточно свобод- । ного места, можно выгрузить самые старые сегменты из физической памяти на диск и на их место загрузить новый сегмент. Процессор может оказать помощь операционной системе в определении тех сегментов, к которым было обращение. Для этих сегментов бит обращения А устанавливается процессором в 1. Сбросить бит обращения можно только из программы, поэтому такая работа возлагается на саму операционную систему. Описанная выше схема реализации виртуальной памяти со свопингом сегмен- тов реально используется в операционной системе OS/2 версий от 1.0 до 1.3. Однако у этой схемы есть один серьёзный недостаток. Так как все сегменты имеют разные размеры и все они подкачиваются по очереди (и по нескольку штук) в одну область физической памяти, возможно возникновение фрагмента- : ции физической памяти. Например, был удалён сегмент размером в 10 Кбайт и j образовался свободный участок физической памяти такого же размера. Новый сегмент, который требуется "закачать” в память, имеет размер 15 Кбайт, и он не поместится на место старого. ; Операционная система может выполнить перемещение сегментов в физичес- > кой памяти, изменив соответствующим образом 24-битовые базовые адреса сег- ! ментов в таблицах дескрипторов. После перемещения сегментов можно объе- динить все свободные участки памяти в один и использовать этот участок для за- грузки нового сегмента. Так как программы защищённого режима не знают фи- зических адресов памяти (они работают только с селекторами), перемещение се- гментов никак не отразится на их работе. Но на перемещение сегментов требуется время, и, кроме того, часто нужен не весь сегмент, а только его небольшой участок. Процессор i80286 не предлагает никакого решения проблемы фрагментации физической памяти при свопинге се- гментов и не позволяет загружать сегмент по частям. Все эти возможности име- ются только в процессорах i80386 и i8O486. Только эти процессоры позволяют , эффективно реализовать механизм виртуальной памяти.
Глава 2 ВХОДИМ В ЗАЩИЩЁННЫЙ РЕЖИМ 'Ли ' Задача второй главы - показать на простом примере, как составить программу для MS-DOS, переключающую процессор из реального режима в защищённый й возвращающую его обратно в реальный режим. Сам процесс описан во многих книгах, посвящённых i80286, однако при этом обычно опускаются многие техни- ческие детали, связанные с аппаратным обеспечением компьютера. Знание этих деталей совершенно необходимо для успешного использования защищённого ре- жима на реальных компьютерах. Сейчас мы не будем рассматривать процесс обработки прерываний в защи- щённом режиме - это материал следующей главы. Там же будет приведён и со- ответствующий пример программы. В программе, которую представим в этой главе, мы запретили прерывания на всё то время, пока процессор находится в защищённом режиме. Подготовка к переключению в защищённый режим Перед тем, как переключить процессор в защищённый режим, надо выполнить некоторые подготовительные действия, а именно: Подготовить в оперативной памяти глобальную таблицу дескрипторов GDT. В этой таблице должны быть созданы дескрипторы для всех сегмен- тов, которые будут нужны программе сразу после того, как она переклю- чится в защищённый режим. Впоследствии, находясь в защищённом режи- ме, программа может модифицировать GDT (если, разумеется, она рабо- тает в нулевом кольце защиты). Программа может модифицировать имею- щиеся дескрипторы или добавить новые, загрузив заново регистр GDTR. Для обеспечения возможности возврата из защищённого режима в реаль- ный необходимо записать адрес возврата в реальный режим в область дан- ных BIOS по адресу 0040h:0067h, а также записать в CMOS-память в ячейку OFh код 5. Этот код обеспечит после выполнения сброса процессо- ра передачу управления по адресу, подготовленному нами в области дан- ных BIOS по Адресу OO4Oh:OO67h. Запретить все маскируемые и немаскируемые прерывания. Открыть адресную линию А20. Запомнить в оперативной памяти содержимое сегментных регистров, кото- рые необходимо сохранить для возврата в реальный режим, в частности указатель стека реального режима. Загрузить регистр GDTR. Первый шаг, связанный с подготовкой GDT, мы уже описали, когда рассказы- вали о преобразовании адресов в защищённом режиме. Что же касается возврата из защищённого режима в реальный, то он выполня- ется сбросом процессора, инициированного выводом определённого байта в про- ’ДИЛЛОЛ-МИФИ'
32 Защищённый режим процессоров Intel 80286/80386/80486 цессор клавиатуры 8042. Это связано с тем, что разработчики процессора i80286 не предусмотрели никакой команды для переключения процессора из защищён- ного режима в реальный. Есть ещё один способ возврата в реальный режим, ос- нованный на переводе процессора в состояние отключения; он будет описан в главе, посвящённой обработке прерываний в защищённом режиме. После выполнения сброса (или после отключения) процессор переходит в ре- альный режим и управление передаётся в BIOS. BIOS анализирует содержимое ячейки CMOS-памяти с адресом OFh - байта состояния отключения. Дальнейшие действия определяются содержимым этой ячейки. Байт состояния отключения OFh используется BIOS для определения способа возврата из защищённого режима в реальный после аппаратного сброса. В табл. 3 перечислены возможные значения для байта состояния отключения. Таблица 3. Значения байта состояния отключения Значение Причина отключения 0 Программный сброс при нажатии комбинации клавиш CTRL-ALT-DEL или неожиданный сброс. Выполняется обычный перезапуск системы, но процедуры тестирования при включении питания не выполняются 1 Сброс после определения объёма памяти 2 Сброс после тестирования памяти 3 Сброс после обнаружения ошибки в памяти (контроль чётности) 4 Сброс с запросом перезагрузки 5 После сброса перезапускается контроллер прерываний, затем управление передаётся по адресу, который находится в области данных BIOS 0040h:0067h 6 ,7,8 Сброс после выполнения теста работы процессора в защищённом режиме 9 Сброс после выполнения пересылки блока памяти из основной памяти в расширенную OAh После сброса управление немедленно передаётся по адресу, взятому из области данных BIOS 0040h:0067h Для обеспечения возврата в реальный режим после сброса по адресу, записан- ному в области данных BIOS 0040h:0067h, можно использовать байты 5 и OAh. Из-за особенностей обработки прерываний в защищённом режиме, которые мы рассмотрим в третьей главе, перед переключением в защищённый режим не- обходимо перепрограммировать контроллер прерываний. Восстановить состояние контроллера после возврата в реальный режим можно автоматически, если ис- пользовать значение 5 для байта состояния отключения. Если же вы не используете прерывания и соответственно не перепрограмми- руете контроллер прерываний, можно использовать значение OAh, при этом пос-
Входим в защищённый режим 33 ле сброса управление будет сразу передано по адресу, взятому из области дан- ных BIOS 0040h:0067h. В этом случае затраченное на возврат в реальный режим время будет меньше. В следующем фрагменте программы мы записываем в ячейку CMOS-памяти с адресом OFh значение 5. Напомним, что для записи числа в ячейку CMOS-памяти необходимо вначале в порт с адресом 70h записать номер нужной ячейки, а затем в порт 7lh - запи- сываемые данные. Не удивляйтесь, что в этом фрагменте программы вместо ячейки OFh указано значение 8Fh, - это не ошибка. Напомним, что единственный способ замаскиро- вать немаскируемые прерывания в компьютере IBM АТ - это записать в порт 70h байт, в котором старший бит установлен в 1. Поэтому наш фрагмент прог- раммы не только записывает байт состояния отключения, но и маскирует немас- кируемые прерывания (!). Нам необходимо также замаскировать обычные пре- рывания, поэтому мы выдаём команду CLI. cli mov al,8f out CMOS_PORT.al jmp nextl ; небольшая задержка nextl: mov al,5 out CMOS_PORT+1,al Следующий шаг - открытие адресной линии А20 - необходим в том случае, если ваша программа будет обращаться к оперативной памяти, лежащей за пре- делами первого мегабайта. Приведём процедуру, которую можно использовать для этой цели: , Процедура открывает адресную линию А20 PROC enable_a20 NEAR mov al,A20_PORT out STATUS_PORT,al mov al,A20_ON out KBD_PORT_A,al ret ENDP enable_a20 Эта магическая последовательность команд выдаёт команду A20_ON клавиа- турному процессору 8042, к которому подключены схемы управления адресной линией А20. После начального сброса линия А20 закрыта и расширенная память за границами первого мегабайта недоступна. Следующий этап - запоминание содержимого сегментных регистров, которые будут нужны при возврате в реальный режим. Это сегментные регистры SS и ES: mov [real_ss],ss ; запоминаем указатель стека mov [real_es],es ; для реального режима ’ДИАЛОГ-МИФИ' Z- 9£Ч
34 Защищённый режим процессоров Intel 80286/80386/80486 На последнем перед переключением в защищённый режим этапе мы загружаем регистр GDTR адресом подготовленной заранее GDT: igdt [QWORD gdt_gdt] Всё! Можно переключаться в защищённый режим! Переключение в защищённый режим Это самый простой этап. Для перевода процессора i80286 из реального режи- ма в защищённый можно использовать специальную команду LMSW. загружаю- щую регистр состояния процессора (Mashine Status Word). Младший бит этого регистра указывает режим работы процессора. Значение, равное 0, соответствует реальному режиму работы, а значение 1 - защищённому. Если установить младший бит регистра состояния процессора в 1, процессор переключится в защищённый режим: mov ах, 1 Imsw ах Однако с помощью команды LMSW невозможно переключить процессор обра- тно в реальный режим. Для этого необходимо использовать другой способ. Возврат в реальный режим Для того чтобы вернуть процессор 80286 из защищённого режима в реальный, необходимо выполнить аппаратный сброс (отключение) процессора. Это можно сделать следующим образом: mov ах, 0FEh ; команда отключения out 64h, ах Перед выдачей команды отключения необходимо запомнить содержимое реги- стра SP, т. к. после передачи управления по адресу, записанному в области дан- ных BIOS 0040h:0067h, регистры SS:SP будет указывать на стек BIOS. После выдачи команды отключения надо подождать, когда произойдёт сброс процессора. Это можно сделать, выдавая в цикле команду HLT. Вот фрагмент программы, возвращающий процессор в реальный режим: , Запоминаем содержимое указателя стека, т. к после ; сброса процессора оно будет потеряно mov [real_sp),sp ; Выполняем сброс процессора mov al,SHUT_DOWN out STATUS_PORT,al ; Ожидаем сброса процессора wait_reset: hit jmp wait_reset
Входим в защищённый режим 35 Далее необходимо восстановить содержимое сегментных регистров, записан- ное в оперативную память на этапе подготовки к переключению в защищённый режим, закрыть адресную линию А20 и размаскировать прерывания. Для закрытия линии А20 можно воспользоваться следующей процедурой: ; Процедура закрывает адресную линию А20 PROC,disable_a20 NEAR mov al,A20_PORT out STATUS_PORT,al mov al,A20_OFF out KBD_PORT_A,al ret ENDP disable_a20 Следующая последовательность команд размаскирует все прерывания: mov ax,000dh ; разрешаем немаскируемые прерывания out CMOS_PORT,al in al,INT_MASK_PORT ; разрешаем маскируемые прерывания and al,0 out INT_MASK_PORT,al sti Теперь, когда мы знаем всё, что нужно для переключения процессора в защи- щённый режим и возврата в реальный режим, можно приступить к практической работе в защищённом режиме. Пример простой программы переключения режима Данная программа запускается в реальном режиме в среде MS-DOS, переклю- чает процессор в защищённый режим, выдаёт сообщение и через некоторое вре- мя возвращает процессор в реальный режим, стирает экран и завершает своё вы- полнение. Программа подготовлена с помощью транслятора Borland Turbo Assembler и использует режим IDEAL. Для её трансляции был использован следующий кома- ндный файл: tasm %1.asm /1 /zi tlink %1.obj /v Вы можете запускать эту программу на любой машине, совместимой с IBM АТ и оборудованной процессорами i80286, i80386, i80486. Но вы не долж- ны запускать эту программу, если у вас компьютер на базе процессоров i80386 или 180486 и активны драйверы QEMM, EMM386; отключите эти драйверы. Кро- ме того, эту программу нельзя запускать на виртуальной машине в среде Microsoft WINDOWS в режиме Enchanced Mode или на виртуальной машине в среде OS/2 версии 2.0. "ДИАЛОГ-МИФИ’
36 Защищённый ражим процессорсв Intel 80286/80386/8G486 Эгк- связано с тем, что в перечислении х выше случаях процессор работает не в реальном режиме, а в так называемом режиме виртуального процессора 8086. Этот режим возможен только для процессоров i80386 или i80486. Кроме того, не следует запускать эту программу на компьютерах серии PS/2 т. к. в них используется другой способ управления линией А20 и другой способ сброса процессора для возврата в реальный режим. Вы можете использовать эту программу для первых экспериментов с защи- щённым режимом. Обратим ваше внимание на некоторые ограничения защищённого режима. Эти ограничения связаны в основном с использованием прерываний и сегментных регистров. Вашей программе, работающей в защищённом режиме, недоступны ни прерывания BIOS, ни прерывания DOS. Любой обмен данными с перифе- рийными устройствами (дисплеем, клавиатурой, диском или принтером! должен выполняться на уровне команд ввода/вывода То есть программе должна работать непосредственно с портами аппаратуры компьютера Это ограничение связано с тем, что обработчики прерываний BIOS и DOS рассчитаны на работу в реальном режиме процессора- Попытка вызова этих об- работчиков в защищённом режиме неизбежно приведёт к аварийному заверше- нию программы Поэтому в приведённой ниже прщрамме вывод текстовых строк на экран про- изводится при помощи непосредственной записи в память видеоконтроллера. Что же касается ввода данных с клавиатуры. то здесь не обойтись без обработки пре- рывания от клавиатуры В следующий главе мы приведём пример программы, которая не только выводит данные на экран дисплея (так же через запись в ви деопамять). но и умеет работать с клавиатурой и таймером Если ваша программа составлена на языках высокой) уровня (Си или Пас- каль) . ей недоступна практически вся библиотека стандартных функций. Особен но это касается функций ввода/вывода и управления памятью. Причина очевид- на - большинство функций стандартных библиотек трансляторов вызывает те или иные прерывания BIOS или DOS. Программы не должны загружать в ич-ментные регистры значения, кото- рые не являются правильными селекторами, описанными в соответствую ших дескрипторных таблицах. Несмотря на то что сама по себе загрузка произвольного значения в сегментный регистр не опасна, попытка исполь- зования неправильно загруженного сегментного регистра вызовет аварий- ное завершение работы программы Это ограничение связано г механизмом преобразования логического адреса в физический. Итак, наша первая программа для защищённого режима процессора 80286:
Входим в защищённый режим 37 Листинг 1. Демонстрация переключения в защищённый режим и возврата об- ратно в реальный режим. IDEAL RADIX 16 Р286 , Используем модель памяти LARGE, при этом мы организуем ; несколько отдельных сегментов и для каждого сегмента ; создадим дескриптор в таблице GDT. MODEL LARGE Определения структур данных и констант STRUC desc_struc ; структура дескриптора limit dw 0 ; предел base_l dw 0 ; мл. слово физического адреса base_h db 0 ; ст байт физического адреса access db 0 ; байт доступа rsrv dw 0 ; зарезервировано EQU EQU EQU EQU EQU EQU ENDS desc_struc , Биты байта доступа ACC_PRESENT ACC_CSEG ACC_DSEG ACC_EXPDOWN ACC_CONFORM ACC_DATAWR ; Типы сегментов ; сегмент данных DATA_ACC - ACC_PRESENT OR ACC_DSEG OR ACC_DATAWR 10000000b сегмент 00011000b сегмент кода 00010000b , сегмент данных 00000100b ; сегмент расширяется вниз 00000100b , согласованный сегмент 00000010b ; разрешена запись есть в памяти , сегмент кода CODE_ACC = ACC_PRESENT OR ACC_CSEG OR ACC_CONFORM ; сегмент стека STACK_ACC - ACC_PRESENT OR ACC_DSEG OR ACC_DATAWR OR ACC_EXPDOWN , Константы STACK_SIZE EQU 0400 ; размер стека B_DATA_SIZE EQU 0300 . размер области данных BIOS B_DATA_ADDR EQU 0400 ; адрес области данных BIOS MONO_SEG EQU 0b000 ; сегмент видеопамяти ; монохромного видеоадаптера COLOR_SEG EQU 0Ь800 ; сегмент видеопамяти ; цветного видеоадаптера CRT_SIZE EQU 4000 ; размер сегмента видеопамяти ; цветного видеоадаптера MONO_SIZE EQU 1000 ; размер сегмента видеопамяти ; монохромного видеоадаптера CRT_LOW EQU 8000 ; мл. байт физического адреса сегмента ; видеопамяти цветного видеоадаптера "ДИАЛОГ-МИФИ
38 Защищённый режим процессоров Intel 80286/80386/80486 MONO_LOW EQU 0000 CRT_SEG EQU 0Bh ; мл. байт физического адреса сегмента видеопамяти монохромного видеоадаптера ; ст байт физического адреса ; сегмента видеопамяти , Селекторы, определенные в таблице GDT DS_DESCR CS_DESCR SS_DESCR BIOS_DESCR = CRT_DESCR = MDA-DESCR = kgdt_ds - gdt_0) i.gdt_cs - gdt_0J i.gdt_ss - gdt_0) (gdt_bio - gdt_0) (gdt_crt - gdt-0) (gdt_mda - gdt_0> CMOS_PORT EQ'J P0RT_6845 EQ’J COLOR PORT EQU MONO_PORT EQU STATUS-PORT EQU SHUT DOWN EQU VIRTUAL-MODE EQJ A20_FORT EQU A20_ON EQU A20_OF EQU KBD_PORT_A EQU KBD_PORT_B EQU *INT_MASK_PORT EQU STACK STACK SIZE 7fJh 0063h 03d4h 03b4h 64b 0feh 0001 h 0dlh 0dfh 0ddh 60h 6ih 21h порт для доступа к CMOS-памяти адрес области данных BIOS. где записано значение адреса порта контроллера 6845 порт цветного видеоконтроллера порт монохромного видеоконтроллера порт состояния клавиатуры команда сброса процессора бит перехода в защищенный режим команда управления линией А20 открыть А20 закрыть А20 адреса клавиатурных портов порт для маскирования прерываний' , сегмент стека DATASEG ; начало сегмента данных DSEG_BEG = THIS WORD , Память для хранения регистров SS, SP, ES Содержимое этих , регистров будет записано здесь перед входом в защищенный , режим и восстановлено отсюда после возврата из защищенного ; режима в реальный real_ss dw ? real_sp dw ? real_es dw ? , Глобальная таблица дескрипторов GDT. содержит дескрипторы ; gdt_0 - дескриптор для пустого селектора gdt gdt - дескриптор для GDT' ; gdt_ds - дескриптор для сегмента, адресуемого DS gdt_cs - дескриптор для сегмента кода gdt_ss - дескриптор для сегмента стека gdt_bio - дескриптор для области данных BIOS ; gdt_crt - дескриптор для видеопамяти цветного дисплея ; gdt.mda - дескриптор для видеопамяти монохромного , дисплея GDT. BEG = $ LABEL gdtг WORD gdt—0 desc_struc <0,0,0,0,0> gdt_gdt desc_struc <GDT_SIZE-1,, DATA_ACC,0>
Входим в защищённый режим 39 gdt_ds desc_struc <DSEG_SIZE-1,,,DATA_AcC,0> gdt_cs desc_struc <CSEG_SIZE-1,,,CODE ACC,0> gdt-_ss desc_struc <STACK SIZE-1,,DATA ACC,0> gdt_bio aesc.struc <E_DATA_SIZE-1 B_DATA ADDF.0,DATA_ACC,0> gdt_crt desc_scruc <CRT_SIZE-1 CR1_LOW,CRT_SEG,DATA_ACC,0> gdt_mda desc_struc <MONO_SIZE-1,MONO_LOW,CRT_SEG,DATA_ACC,0> GDT_SIZE = ($ - GDT_BEG) . размер таолицы дескрипторов CODESEG , сегмент кода PROC start Инициализируем регистр сегмента данных для реального режима mov ax.DGRO’JP mov ds,ах , Определяем базовый адрес видеопамяти call set_crt_base ; Стираем экран дисплея (устанавливаем серый фон) mov bh, 77h call drscr ; Подготовка к переходу в защищенный режим и обеспечение возможности возврата в реальный режим call init_protected_mode Переключаемся в защищенный режим са)1 set_protected_mode ; ------- * Программа работает в защищенном режиме! * ------- call write_bello._msg выводим сообщение на экран са)1 pause ждем некоторое время , Возвращаемся в реальный режим call set_real_mode , ------- ’ Программа работает в реальном режиме! ' ------- , Стираем экран и возвращаемся в DOS mov bh, 07h . call clrscr mov ah,4Ch | int 21h ENDP start Макрокоманда для записи в дескриптор 24-битового базового адреса сегмента MACRO setgdtentry mov [(desc_struc bx).base_l1,ax mov [(desc struc bx).base_hj,dl ENDM ’ДИАЛОГ-МИФИ1
40 Защищённый режим процессоров Intel 80286/80396/80486 Процедура подготовки процессора к переходу в защищенный режим с последующим возвратом в реальный режим PROC init_protected_mode NEAP , Заполняем глобальную таблицу дескрипторов GDT ; Вычисляем 24-битовый базовый адрес сегмента данных mov ах,DGROUP mov dl,ah shr dl,4 shl ax,4 , Регистры dl ax содержат базовый адрес, сохраняем его в di:-si mov ai,ах mov di.dx Подготавливаем дескриптор для GDT add ах,OFFSET gdtr adc dl,0 mov bx,OFFSET gdt_gdt setgdtentry .; Подготавливаем дескриптор для сегмента ds mov bx.OFFSET gdt_ds mov ax,s i mov dx,di setgdtentry ; Подготавливаем дескриптор для сегмента cs mov bx,OFFSET gdt_cs mov ax,cs mov dl.ah shr dl,4 shl ax, 4 setgdtentry ; Подготавливаем дескриптор для сегмента стека mov bx,OFFSET gdt_ss mov ax,ss mov dl ah shr dl 4 shl ax,4 setgdtentry Записываем адрес возврата в реальный режим в область , данных BIOS по адресу 0040h 0067h push ds mov ax,40 mov ds, гос mov 'WORD 67 J OFFSET shutdown_return mov 'WORD 69 j,cs pop ds ; Маскируем все прерывания в том числе немаскируемые. . Записываем в CMOS-память в ячейку 0Fh код 5, ; этот код обеспечит после выполнения сброса процессора
Входим в защищённый режим 41 ; передачу управления по адресу, подготовленному нами в области данных BIOS по адресу 0040h 0067h Для того, чтобы немаскируемые прерывания были запрещены, устанавливаем в 1 старший бит при определении ячейки CMOS cli mov al 8f out CMOS_PORT al jmp nextl . небольшая задержка nextl mov al, 5 out CMOS_PORT+1,al ; код возврата ret ENDP init_protected_mode . Процедура переключает процессор в защищенный режим PROC set_ protected_mode NEAR mov ax (rl_crt] записываем в es сегментный mov es, ax , адрес видеопамяти call enable_a20 . открываем адресную линию А2И mov [real ss],ss ; запоминаем указатель стека mov [ real_es),es ; для реального режима Загружаем регистр GDTR Igdt [QWORD gdt_gdt] Устанавливаем защищенный режим работы процессора mov ах,VIRTUAL-MODE Imsw ах , Мы находимся в защищенном режиме ; Очищаем внутреннюю очередь команд процессора. Выполняем команду межсегментного перехода, . в качестве селектора указываем селектор текущего , сегмента кода, в качестве смещения - метку -ilush , jmp far flush db 0ea dw OFFSET flush aw CS-DESCR LABEL flush FAR , Загружаем сегментные регистры SS и DS селекторами mov ax.SS, DESCR mov ss, ax mov ax,DS_DESCR mov ds .ax ret ENDF set_protected_mode 'ДИАЛОГ-МИФИ'
42 Защищённый режим процессоров Intel 80286/80386/80486 Процедура возвращает процессор в реальный режим PROC set_real_mode HEAR ; Запоминаем содержимое указателя стека, т. к. после , сброса процессора оно будет потеряно mov [real_sp],sp , Выполняем сброс процессора mov al .SHUTDOWN out STATUS_PORT,al ; Ожидаем сброса процессора wait_reset: hit jmp wait_reset ; ------->> В это место мы попадем после сброса процессора, ; теперь мы снова в реальном режиме LABEL shutdown_return FAR ; Инициализируем ds адресом сегмента данных mov ax.DGROUP mov ds,ах assume ds.DGROUP Восстанавливаем указатель стека mov ss (real_ss| mov sp,[real_spi Восстанавливаем содержимое регистра es mov es,[real_esj ; Закрываем адресную линию A20 call disable_a20 , Разрешаем все прерывания mov ax,000dh ; разрешаем немаскируемые прерывания out CMOS_PCRT,al in al,1NT_MASK_PORT разрешаем маскируемые прерывания and al ,0 out I NT .MASK. _PORT, al sti ret E1IDP set real mode Процедура открывает адресную линию а20 PROC enable_a20 NEAR mov al,A20_PORT out STATUS_PORT,a] mov al,A20_ON out KBDPORT_A,al ret ENDP enable_a20
Входим в защищённый режим 43 Процедура закрывает адресную линию А20 PROC disable_a20 NEAR mov a],A20_PORT out STATUS_PORT,al mov aJ ,A20_OFF out KBD_PORT_A,al ret ENDP disable_a20 Процедура выполняет небольшую временную задержку PROC pause NEAR push ex mov ex,50 ploop0. push ex xor ex,ex ploopl loop ploopl pop ex loop ploop0 pop ex ret ENDP pause ; Сегмент данных для процедур обслуживания видеоадаптера DaTASEG columns db 80d ; количество столбцов на экране rows db 25d ; количество строк на экране rl_crt dw COLOR_SEG сегментный адрес видеобуфера vir_crt dw CRTDESCR , селектор видеобуфера curr_line dw 0d ; номер текущей строки CODESEG Определение базового адреса видеобуфера PROC set_crt_base NEAR . Определяем количество столбцов на экране и записываем , в переменную columns mov ах,40 mov es, ах mov ox,[WORD es 4a] mov [columns],bl . To же для количества строк, записываем в переменную rows mov Dl,(BYTE es 84 J inc ol mov [rows],bl ‘ДИАЛ01 -МИФИ’
44 Защищённый режим процессоров Intel 80286/80386/80486 ; Для того чтобы определить тип видеоконтроллера (цветной ; или монохромный), считываем адрес микросхемы 6845 mov bx,[WORD es'P0RT_6845] crop bx COLOP_PORT je set_crt_exit ; Если видеоконтроллер монохромный изменяем адрес сегмента , и селектор, заданные по умолчанию mov [гl_crt],MONO_SEG mov [ vir_crt, ] , MDA_DESCR set_crt_exit ret ENDP set_crt_base । Вывод строки на экран Параметры: (ах, Ъх) - координаты (х, у) выводимой строки ds si - адрес выводимой строки сх - длина выводимой строки dh - атрибут выводимой строки es - сегмент или селектор видеопамяти PROC writexy NEAR push si push di . Вычисляем смещение в видеобуфере для записи строки, .. используем формулу ((у ' columns) + х) ‘ 2 mov dl,[columns] mu 1 d 1 add ax,bx shl ax,l mov d i , ax mov ah,dh ; записываем в ah байт атрибута , Выполняем запись в видеобуфер wxy_write. lodsb ; очередной символ в al stosw , записываем его в видеопамять loop wxy_write цикл до конца строки pop di pop si ret ENDP writexy Процедура стирания экрана Параметр bh - атрибут для заполнения экрана PRCC clrscr NEAR хог сх.сх mov dl,[columns] mov dh,[rows] mov ax,0600h
Входим в защищённый режим 45 int 10h ret ENDP clrscr □ATASEG he]lo_msg db ’ Protected mode monitor 'TINY/OS* , v.l 0 for CPU 80286 | (C) Frolov A V , 1992 " CODF.SEG ; Процедура выводит сообщение в защищенном режиме f’RUC write_hello_msg NEAR mov ax,[vir_crt] ; загружаем селектор видеопамяти mov es.ax ; в регистр es , Выводим сообщение в верхний левый угол экрана (х = у = 0) mov bx,0 ;(X,Y) = (АХ.ВХ) mov ах,[curr_lзne1 inc [curr_line] увеличиваем номер текущей строки . Загружаем адрес выводимой строки и ее длину mov si,OFFSET hello_msg mov ex,SIZE hello_msg mov dh,30h ; атрибут - черный текст на голубим фоне call writexy ; выводим строку ret ENDP write_hello_msg CSEG_SIZE = ($ - start) , размер сегмента кода DATASEG DSEG_STZE = 1$ - DSEG_BEG) , размер сегмента данных END start "ДИАЛОГ-МИФИ1
Глава 3 ОБРАБОТКА ПРЕРЫВАНИЙ В ЗАЩИЩЁННОМ РЕЖИМЕ Механизм обработки прерываний в защищённом режиме сильно отличается от механизма реального режима. До сих пор мы ничего не говорили о прерывани- ях, в приведённом выше примере программы перед переходом в защищённый режим мы просто зама>.кировали все прерывания. Однако такой способ "реше- ния” проблемы прерываний подходит не всегда. В этой главе мы расскажем вам о гом, как надо работать с прерываниями в за- щищённом режиме и приведём соответствующий пример программы Вы научи- тесь обрабатывать в защищённом режиме не только программные прерывания, но и аппаратные, что необходимо, в частности, для создания драйверов Прерывания в реальном режиме В главе 4 первой книги первого тома серии ’Библиотека системного програм- миста", который называется "Операционная система MS-DOS”, мы подробно рассказали об особенностях обработки прерываний в реальном режиме. Напомним только основные моменты. В реальном режиме имеются программные и аппаратные прерывания. Прог- раммные прерывания инициируются командой INT. аппаратные внешними со- бытиями асинхронными по отношению к выполняемой программе. Обычно ап- паратные прерывания инициируются аппаратурой ввода/вывода после заверше- ния выполнения текущей операции. Кроме того, некоторые прерывания зарезервированы для использования са- мим процессором - прерывания по ошибке деления, прерывания для пошаговой работы, немаскируемое прерывание и т. д. Для обработки прерываний в реальном режиме процессор использует таблицу векторов прерываний. Эта таблица располагается в самом начале оперативной памяти, т. е. её физический адрес - 00000. Таблица векторов прерываний реального режима состоит из 256 элементов по 4 байта, поэтому её размер составляет 1 Кбайт. Элементы таблицы - дальние указатели на процедуры обработки прерываний Указатели состоят из 16-битсво- го сегментного адреса процедуры обработки прерывания и 16-битового смеще- ния. Смещение хранится по младшему адресу, сегментный адрес - по старшему Когда происходит программное или аппаратное прерывание, текущее содер- жимое регистров CS, IP а также регистра флагов FLAGS записывается в стек программы (который, в свою очередь, адресуется регистровой парой SS:SP). Да- лее из таблицы векторов прерываний выбираются новые значения для CS и IP при этом управление передаётся на процедуру обработки прерывания Перед входом в процедуру обработки прерывания принудительно сбрасывают ся флажки трассировки TF и разрешения прерываний IF. Поэтому, если ваша
Обработка прерываний в защищённом режиме 47 процедура прерывания сама должна быть прерываемой, вам необходимо разре- шить прерывания командой STI. В противном случае до завершения процедуры обработки прерывания все прерывания будут запрещены. Завершив обработку прерывания, процедура должна выдать команду IRET, по ней из стека будут извлечены значения для CS, IP, FLAGS и загружены в соот- ветствующие регистры. Далее продолжается выполнение прерванной программы. Что же касается аппаратных маскируемых прерываний, то в компьютере IBM АТ и совместимых с ним существует всего шестнадцать таких прерываний, обозначаемых IRQ0-IRQ15 В реальном режиме для обработки прерываний 1RQ0-IRQ7 используются векторы прерывании от o8h до ОГЬ, а для IRQ8- 1RQ15 - от 70h до 77b. Прерывания защищённого режима В защищённом режиме все прерывания разделяются на два типа - обычные прерывания и исключения (exception - исключение, особый случай). Обычное прерывание инициируется командой INT (программное прерывание) или внешним событием (аппаратное прерывание) Перед передачей управления процедуре обработки обычного прерывания флаг разрешения прерываний IF сбрасывается и прерывания запрещаются Исключение происходит в результате ошибки, возникающей при выполнении какой-либо команды, например если команда пытается выполнить запись данных за пределами сегмента данных или использует для адресации селектор, не опре- делённый 1 таблице дескрипторов По своим функциям исключения соответству- ют зарезервированным для процессора внутренним прерываниям реального ре- жима. Когда процедура обработки исключения получает управление, флаг IF не изменяется. Поэтому в мультизадачной среде особые случаи, возникающие в от- дельных задачах, не оказывают влияния на выполнение остальных задач. В защищённом режиме прерывания могут приводить к переключению задач. О задачах и мультизадачное™ мы будем говорить в следующей главе Теперь перейдём к рассмотрению механизма обработки прерываний и исклю- чений в защищённом режиме Таблица прерываний защищённого режима Обработка прерываний и исключений в защищённом режиме по аналогии с реальным режимом базируется на таблице прерываний. Но таблица прерываний защищённого режима является таблицей дескрипторов, которая содержит так на- зываемые вентили прерываний, вентили исключений и вентили задач. Таблица прерываний защищённого режима называется дескрипторной табли- цей прерываний IDT (Interrupt Descriptor Table). Так же как и таблицы GDT и LDT, таблица IDT содержит 8-байтовые дескрипторы (рис. 12) Причём это системные дескрипторы - вентили прерываний, исключений и задач. Поле TYPE вентиля прерывания содержит значение б, а вентиля исключения - значение 7. ДИАЛОГ-МИФИ’
ля Защищённый режим процессоров Intel 80286/80386/80486 Резерв I Доступ Саг «ктоо | Смещение 16 бит I В бит бит 18 бит 16 бит Пол» доступ* •нтиля прерывания |.»|рр| |к[о| ТрТо1 7 6 3 4 3 2 1 0 Пола ддотуп* мктиля иоключ амия |»>| PPL I 0 I ° 1 , ПТЛ 7 6 3 4 3 2 1 О Рис, 12. Формат элементов дескрипторной таблицы прерываний IDT Где располагается дескрипторная таблица прерываний IDT? Её расположение определяется содержимым 5-байтового внутреннего регистра процессора 1DTR Формат регистра 1DTR полностью аналогичен формату регис- тра GDTR, для его загрузки используется команда LIDT Так же, как регистр GDTR содержит 24-битовый физический адрес таблицы GDT и ее предел, так и регистр IDTR содержит 24-битовый физический адрес дескрипторной таблицы прерываний IDT и её предел. Регистр IDTR обычно загружают перед переходом в защищённый режим. Ра- зумеется, это можно сделать и потом, находясь в защищённом режиме Однако для этого программа должна работать в привилегированном нулевом кольце. Исключения в защищённом режиме Для обработки особых ситуаций - исключений - разработчики процессора i80286 зарезервировали 31 номер прерывания. В табл. 4 приведён полный список зарезервированных прерываний защищённого режима. Таблица 4. Зарезервированные прерывания защищённого режима Код Прерывание 00h 01 h 02h 03h 04 b Ошибка при выполнении команды деления Прерывание для пошаговой работы, используется отладчиками Немаскируемое прерывание Прерывание по точке останова для отладчиков Переполнение, генерируется командой INTO, если установлен флаг OF 05h Генерируется при выполнении машинной команды BOUND, если проверяемое значение вышло за пределы заданного диапазона 06h Недействительный код операции, или длина команды больше 10 байт 07h 08 h Отсутствие арифметического сопроцессора Двойная ошибка, вырабатываемся в том случае, если при обработке исключения возникло ещё одно исключение. Если во время обра- ботки этого прерывания возникает грегье исключение, процессор
Обработка прерываний в защищённом режиме 49 переходит в состояние отключения, что приводит к перезапуску процессора 09h Превышение сегмента арифметическим сопроцессором Одр Недействительный сегмент состояния задачи TSS UBh Отсутствие сегмента Вырабатывается при попытке использовать для адресации дескриптор, у которого бит присутствия сегмента в памяти Р сброшен в U. Это прерывание используется для реализации механизма виртуальной памяти. В этом случае по прерыванию OBh операционная система может выполнить ’’подкачку" отсутствующего сегмента в память ОСЬ Исключение при работе со стеком. Может возникать в случае отсу гствия сегмента стека в памяти или в случае переполнения (антипереполнения) стека ODh Исключение по защитг памяти. Возникает при любых попытках получения доступа к сегментам памяти, если программа обладает недостаточным уровнем привилегий OEh Отказ страницы для процессоров i80386 или 180486, зарезервировано для i80286 OFh Зарезервировано 1 Oh Исключение сопроцессора Uh - lAh Зарезервированы Перед тем, как передать управление обработчику исключения, для многих за- резервированных прерываний процессор помещает в стек ) 6-битовый код ошиб- ки. Этот код ошибки программа может проанализировать и тем самым получить некоторую дополнительную информацию об ошибке. Формат кода ошибки приведён на рис. 13. 1S 3 2 10 |Индчсе | TI | 1~[fxT~| Рис, 13. Формат кода ошибки процессора i80386 Поле индекса содержит индекс дескриптора, при обращении к которому прои- зошла ошибка. Поле I, равное 1, означает, что индекс относится к таблице IDT В этом случае произошла ошибка при обработке прерывания или исключения. Если бит 1 равен 0, поле Т1 выбирае, таблицу дескрипторов (GDT или LDT) по аналогии с соотвеюгвукядим полем селектора. Бит EXT устанавливается в том случае, когда ошибка произошла не н резуль- тате выполнения текущей команды, а по внешним относительно выполняемой программы причинам Например, при обработке аппаратного прерывания от vc-гройства ввода/вывода произошло обращение к отсутствующему в памяти сег- менту (у которого в дескрипторе сброшен бит присутствия Р). 'ДИАЛОГ-МИФИ'
50 Защищённый режим процессоров Intel 80286/60386/80486 Как мы только что говорили, коды ошибок включаются в стек не для всех ис- ключений. Программа сможет проанализировать этот код только для следующих исключений: 08h - двойная ошибка; OAh - недействительный TSS; OBh - отсутствие сегмента в памяти; ОСЬ - исключение при работе со стеком; ODh - исключение по защите памяти. Заметим, что аналога коду ошибки для зарезервированных прерываний в реальном режиме нет. Кроме того, новым при обработке прерываний в защищённом режиме являет- ся свойство повторной запускаемости исключений. Свойством повторной запускаемое™ обладают не все исключения. Что такое повторная запускаемость? Поясним это на конкретном примере. Пусть в нашей системе реализована виртуальная память. Программа в некоторый момент времени обратилась к отсу- тствующему в оперативной памяти сегменту, выдав какую-либо команду, напри- мер MOV или ADD. Возникло исключение OBh - отсутствие сегмента в памяти. Обработчик этого исключения, входящий в состав операционной системы, выполнил свопинг соот- ветствующего сегмента в опера™вную память. Что дальше? А дальше было бы неплохо повторить выполнение прерванной команды! Это можно сделать, т. к. для всех повторно запускаемых исключений (кроме 03h - прерывание по точке останова и 04h - переполнение) в стек включается адрес не следующей за прерванной командой, а адрес первого байта команды,, которая вызвала исключение. Выполнив команду IRET, программа обработки исключения вновь передаст управление прерванной команде. Свойством повторной запускаемое™ обладает большинство зарезервирован- ных прерываний, кроме следующих: 01 h - прерывание для пошаговой работы; 08h - двойная ошибка; 09h - превышение сегмента сопроцессором; ODh - исключение по защите памяти; 10h - исключение сопроцессора. Обработка аппаратных прерываний Вспомните диапазон номеров прерываний, используемый в реальном режиме в компьютерах IBM PC: для обработки прерываний IRQ0-IRQ7 используются номера прерываний от 08h до OFh, а для IRQ8-IRQ15 - от 70h до 77h. Но в защищённом режиме номера от 08h до OFh зарезервированы для обрабо- тки исключений! К счастью, имеется простой способ перепрограммирования контроллера пре- рываний на любой другой диапазон номеров векторов аппаратных прерываний.
Обработка прерываний в защищённом режиме 51 Например, аппаратные прерывания можно расположить сразу за прерываниями, зарезервированными для обработки исключений. После возврата процессора в реальный режим необходимо восстановить состо- яния контроллера прерываний. Если при подготовке к возврату в реальный режим мы записали в CMOS-память байт состояния отключения со значением 5, после сброса BIOS сам перепрограммирует контроллер прерываний для работы в реальном режиме и нам не надо об этом беспокоиться. В противном случае про- грамма должна установить правильные номера для аппаратных прерываний ре- ального режима. Программа, которая работает с прерываниями Следующая программа выполняет все необходимые действия, связанные с обработкой прерываний и исключений в защищённом режиме. Наша первая программа (листинг 1) работала в защищённом режиме с зап- рещёнными прерываниями. Она как бы пролетала через неизведанное с завязан- ными глазами и сразу же возвращалась в хорошо освоенный реальный режим. Теперь же программа имеет возможность ’’осмотреться” и может реагировать на такие события, как прерывания от клавиатуры и таймера. Кроме того, в случае возникновения исключений вам будет выдана некоторая диагностика, включающая код исключения, код ошибки и содержимое регистров процессора на момент возникновения исключения. Таблица IDT содержит дескрипторы для обработчиков исключений и аппарат- ных прерываний. Вентили исключений содержат ссылки на программы с имена- ми exc_OO...exc_lF. Вслед за вентилями исключений в таблице 1DT следуют вентили аппаратных прерываний. Из них задействованы только 1RQ0 и IRQ1 - прерывания от таймера и клавиатуры Те аппаратные прерывания, которые нас не интересуют, приводят к выдаче в контроллеры прерывания команды конца прерывания. Для таких прерываний предусмотрены заглушки - процедуры с именами dummyJretO (к первому контроллеру прерывания) и dummyjretl (ко второму). Вслед за вентилями аппаратных прерываний мы поместили в таблицу IDT вентиль программного прерывания int 30h, предназначенного для организации взаимодействия с клавиатурой на манер прерывания BIOS INT 16h. При выдаче прерывания int 30h вызывается процедура с именем Int_30h_Entry. После запуска программа переходит в защищённый режим и размаскирует прерывания от таймера и клавиатуры. Далее она вызывает в цикле прерывание int 30h (ввод символа с клавиатуры) и выводит на экран скан-код нажатой кла- виши и состояние переключающих клавиш (таких, как CapsLock, Ins, и т. д.). Если окажется нажатой клавиша ESC, программа выходит из цикла. Далее в тексте программы следует ряд команд, закрытых символом комментария. Эти команды приводят к исключению. Вы можете попробовать их работу, удалив соответствующий символ комментария. При возникновении исключения на экран будет выведена диагностика, о чём позаботится обработчик исключений. 'ДИАЛОГ-МИФИ'
53 Защищённый режим процессоров Intel 80286/80386/80486 Перед завершением работы программа устанавливает реальный режим процес- сора и стирает экран Обработчик аппаратного прерывания клавиатуры - процедура с именем Keyb_int. После прихода прерывания она выдаёт короткий звуковой сигнал, счи- тывает и анализирует скан-код клавиши, вызвавшей прерывание. Скан-коды классифицируются ш. обычные и расширение.- (для 101-клавишной хльвиату ры). В отличие оп прерывания BIOS INT 16h мы для простоты не стали реализо- вывать очередь, а ограничились записью полученною скан кода в глобальную ячейку памяти key_code. Причём прерывания, возникающие при отпусканиг клавиы. игнорируются. Запись скан-кода в ячгйку kcy_code выполняет процедура Keyb„PutQ. После записи эта процедура устанавливает признак того, что была нажата клавиша, записывает значение OFFh - глобальную переменную key flag. Программное прерывание 1ш 30h опрашивает состояние key flag. Если этот флаг оказывается установленным, он сбрасывается, вслед за чем обработчик in: 30b записывает в регистр АХ скан-код нажатой клавиши, в регистр ВХ - со- стояли е переключающих клавиш на момент нажатия клавиши, код которой пе- редан в регистре АХ Для того чтобы не загромождать программу второстепенными деталями, мы не стали перекодировать скан-код и код ASCII, вы сможете при необходимости сде- лать это сами Обработчик прерываний таймера - процедура с именем Timer_int Эта проце- дура примерно раз в секунду выдаёт звуковой сигнал, чем её действия и ограни- чиваются. Процедура rdump выводит на экран содержимое регистров процессора и может быть использована для отладки программы. Обратите внимание на использованный способ возврата процессора в реаль- ный режим: DATASEG ; Пустой дескриптор для выполнения возврата процессора ; в реальный режим через перевод его в состояние отключения null_idt idt.ystruc о CODESEG PROC set_rmode NEAR mov [real_sp],sp ; Переводим процессор в сэсгояние отключения, это эквивалентно ; аппаратному сбросу, но выполняется быстрее Сначала мы ; загружаем IDTR нулями, затем выдаем команду прерывания. lidt [FWQRD null_idt] int 3 rwait. hit jmp rwait LABEL shutdown return TAR
Обработка прорываний в защищённом режиме S3 Регистр IDTR загружается нулями, следовательно, предел дескрипторной таб- дспгы прерываний равен нулю. После этого мы выдаём команду программного прерывания. При обработке прерывания возникает исключение, т. к. регистр IOTR инициализирован неправильно. Но это исключение не может быть обрабо- тано по той же причине, что вызывает новое исключение. Теперь процессор пе- реходит уже в состояние отключения и выполняет рестарт в реальном режиме. Что нам и требовалось получить! Для удобства мы вынесли в отдельный файл tiny-os.inc все необходимые опре- деления структур данных и констант (листинг 2). Файл tiny-os.asm содержит са- му программу, текст которой приведён в листинге 3. Листинг 2. Структуры данных и константы. Определения структур данных и констант STRUC des limit base_l base_h access rsrv ic_struc ; структура дескриптора ; предел ; мл. слово физического адреса ; ст. байт физического адреса ; байт доступа ; зарезервировано dw dw db db dw ic_struc 0 0 0 0 0 ENDS des STRUC idt_struc destoff dw destsel dw nparams db assess db rsrv dw ENDS idt_stpic 0 0 0 0 0 ; вентиль прерывания , смещение обработчика ; селектор обработчика ; количество параметров ; байт доступа ; зарезервировано STRUC idtr_struc idt_lim dw 0 ; регистр IDTR ; предел IDT idt_l dw 0 ; мл. слово физического адреса ENDS idt_h db rsrv db idtr_struc 0 0 ; ст. байт физического ; ; зарезервировано адреса Биты байта доступа ACC_PRESENT EQU 10000000b ; сегмент есть в памяти ACC_CSEG EQU 00011000b ; сегмент кода ACCDSEG EQU 00010000b ; сегмент данных ACC_EXPDOWN EQU 00000100b ; сегмент расширяется вниз ACC_CONFORM EQU 00000100b ; согласованный сегмент ACC DATAWR EQU 00000010b ; разрешена запись acc_int_gate EQU 00000110b ; вентиль прерывания ACC_TRAP_GATE EQU 00000111b ; вентиль исключения , Типы сегментов , сегмент данных ОАТА_АСС = ACC_PRESENT OR ACC_DSEG OR ACC_DATAWR , сегмент кода 'ДИАЛОГ-МИФИ'
54 Защищённый режим процессоров Intel 80286/80386/80486 CODE_ACC = ACC_PRESENT OR ACC_CSEG OR ACC_CONFORM ; сегмент стека STACK_ACC = ACC_PRESENT OR ACC_DSEG OR ACC_DATAWR OR ACC_EXPDOWN ; байт доступа сегмента таблицы IDT IDT_ACC - DATA_ACC ; байт доступа вентиля прерывания INT_ACC - ACC_PRESENT OR ACC_INT_GATE ; байт доступа вентиля исключения TRAP_ACC = ACC_PRESENT OR ACC_TRAP_GATE ; Константы STACKJSIZE EQU 0400 размер стека B_DATA_SIZE EQU 0300 размер области данных BIOS B_DATA_ADDR EQU 0400 адрес области данных BIOS MONO_SEG EQU 0b000 сегмент видеопамяти монохромного видеоадаптера COLOR_SEG EQU 0b800 сегмент видеопамяти цветного видеоадаптера CRT_SIZE EQU 4000 размер сегмента видеопамяти цветного видеоадаптера MONO_SIZE EQU 1000 размер сегмента видеопамяти монохромного видеоадаптера CRT_LOW EQU 8000 мл. байт физического адреса сегмента видеопамяти цветного видеоадаптера MONO_LOW EQU 0000 мл. байт физического адреса сегмента видеопамяти монохромного видеоадаптера CRT_SEG EQU 0Bh ст. байт физического адреса сегмента видеопамяти CMOS_PORT EQU 70h порт для доступа к CMOS-памяти PORT_6845 EQU 006 3h адрес области данных BIOS, где записано значение адреса порта контроллера 6845 COLOR_PORT EQU 03d 4h порт цветного видеоконтроллера MONO_PORT EQU 03b4h порт монохромного видеоконтроллера STATUS_PORT EQU 64h порт состояния клавиатуры SHUTDOWN EQU 0feh команда сброса процессора VIRTUAL_MODE EQU 000 Ih бит перехода в защищ нный режим A20_PORT EQU 0dlh команда управления линией А20 A20_ON EQU 0dfh открыть А20 A20 OFF EQU 0ddh закрыть А20 KBD_PORT_A EQU 60h адреса клавиатурных KBD_PORT_B EQU 61h портов INT_MASK_PORT EQU 21h порт для маскирования прерываний EOI EQU 20 команда конца прерывания MASTER8259A EQU 20 первый контроллер прерываний SLAVE8259A EQU 0a0 второй контроллер прерываний ; Селекторы, определенные в таблице GDT
Обработка прерываний в защищённом режиме 55 DS-DESCR = (gdt_ds - gdt_0) cs_descr = (gdt_cs - gdt_0) SS_DESCR = (gdt_ss - gdt_0) BIOS_DESCR - (gdt_bio - gdt_'0) crt_descr = (gdt_crt - gdt_0) mda_descr = (gdt_mda - gdt_0) ; Маски и инверсные маски для клавиш l_shift equ 0000000000000001b nl_shift equ 1111111111111110b r_shift equ 0000000000000010b nr_shift equ 1111111111111101b l_ctrl equ 0000000000000100b nl_ctrl equ 1111111111111011b r_ctrl equ 0000000000001000b NR-CTRL equ 1111111111110111b L_ALT equ 0000000000010000b NL_ALT equ 1111111111101111b R_ALT equ 0000000000100000b NR_ALT equ 1111111111011111b CAPS_LOCK equ 0000000001000000b SCR_LOCK equ 0000000010000000b NUM_LOCK equ 0000000100000000b INSERT equ 0000001000000000b Листинг 3. Демонстрация обработки прерываний и исключений в защищённом режиме для процессора 80286. IDEAL RADIX 16 Р286 MODEL LARGE include ’tiny-os.inc’ STACK DATASEG DSEG_BEG real real, real GDT_BEG LABEL gdt_0 gdt_gdt STACKJSIZE THIS WORD _ss dw ? _sp dw ? _es dw ? = $ gdtr WORD desc_struc <0,0,0,0,0> desc struc <GDT SIZE-1,, ,DATA_ACC,0 > gdt_idt desc_struc <IDT_SIZE-1,, , IDT_ACC,0> gdt_ds desc_struc <DSEG_SIZE-1, ,,DATA_ACC,0> gdt_cs desc_struc <CSEG_SIZE-1, ,,CODE_ACC,0> gdt_ss desc_struc <STACK_SIZE-1 ,,,DATA_ACC,0> gdt_bio desc_struc <B DATAJSIZE- 1,B_DATA_ADDR,0,DATA_ACC,0> 'ДИАЛОГ-МИФИ
56 Защищённый режим процессоров Intel 80286/80386/80486 gdt_crt descjstruc «CRTJSIZE-l,CRT_LOW,CRT_SEG,DATA_ACC,0> gdtjnda desc_struc «MONO_SIZE-1,MONO_LOW.CRT_SEG.DATA_ACC,0> GDT_SIZE = ($ - GDT_BEG) ; Область памяти для загрузки регистра IDTR idtr idtr_struc <IDT_SIZE,,,0> ; Таблица дескрипторов прерываний IDT_BEG - $ ; ------------------- Вентили исключений ------------------- idt idt_struc «OFFSET exc_00,CS_DESCR,0,TRAP_ACC,0> idt_struc «OFFSET exc_01,CSJDESCR,0,TRAP JiCC,0> idt_struc «OFFSET exc_02,CS_DESCR,0,TRAP_ACC,0> idt_struc «OFFSET exc_03,CSJDESCR,0,TRAP_ACC,0> idt_struc «OFFSET exc_04,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_05,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_06,CS_DESCR,0,TRAP_ACC,0> idtZstruc «OFFSET exc_07,CSJDESCR,0,TRAP_ACC,0> idt_struc «OFFSET exc_08,CS_DESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_09,CSJDESCR,0,TRAP_ACC,0> idt_struc «OFFSET exc_0A,CSJDESCR,0,TRAP_ACC,0> idt_struc «OFFSET exc_0B,CSJDESCR,0,TRAP_ACC,0> idt_struc «OFFSET exc_0C,CSJDESCR.0,TRAP_ACC,0> idtjstruc «OFFSET exc_0D,CS_DESCR.0,TRAP_ACC,0> idt_struc «OFFSET excJDE,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_0F,CS_DESCR,0,TRAP_ACC,0> idt_struc «OFFSET exc_10,CS_DESCR;0.TRAP_ACC,0> idtjstruc «OFFSET exc_l1.CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_12,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_13,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_14,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_15,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_16,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_17,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_18,CSJDESCR.0,TRAP_ACC,0> idtjstruc «OFFSET exc_19,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_lA,CSJDESCR,0,TRAPJ\CC,0> idtjstruc «OFFSET exc_lB,CSJDESCR,0,TRAP_ACC,0> idtjstruc «OFFSET exc_lC,CSJDESCR,0,TRAP_ACC,0> idt_struc «OFFSET excJD, CSJDESCR , 0 , TRAP_ACC , 0> idtjstruc «OFFSET exc_lE,CSJDESCR,0.TRAP_ACC.0> idt_struc «OFFSET excJF, CSJDESCR ,0, TRAP_ACC, 0> ; ---------------Вентили аппаратных прерываний----------------- ; int 20h — IRQ0 idtj:true «OFFSET Timer_int,CSJDESCR,0,INT_ACC,0> ; int 21h -- IRQ1 idtjstruc «OFFSET Keyb_int,CSJDESCR,0,INT_ACC,0> ; int 22h, 23h, 24h, 25h, 26h, 27h — IRQ2-IRQ7 idtjstruc 6 dup («OFFSET dummy_iret0,CSJDESCR,0,INT_ACC,0>) ; int 28h, 29h, 2ah, 2bh, 2ch, 2dh, 2eh, 2fh — IRQ8-IRQ15 idt_struc 8 dup («OFFSET dummy_iretl,CSJDESCR,0,INT_ACC,0>) ; ------------------- Вентиль прерывания ----------------------
Обработка прерываний в защищённом режиме 57 int 30h idt_struc «OFFSET Int_30h_Entry,CS_DESCR,0,INT_ACC,0> IDT_SIZE = ($ - IDT_BEG) CODESEG PROC start mov ax,DGROUP mov ds, ax call set_crt_base mov bh, 77h call clrscr , Устанавливаем защищенный режим call set_pmode call write_hello_msg , Размаскируем прерывания от таймера и клавиатуры in al,INT_MASK_PORT and al,0fch out INT_MASK_P.ORT , al , Ожидаем нажатия на клавишу <ESC> charin int 30h ; ожидаем нажатия на клавишу ; АХ - скан-код клавиши, ; ВХ - состояние переключающих клавиш cmp al, 1 ; если <ESC> - выход из цикла jz continue push bx ; выводим скан-код на экран mov bx, 0301h ; координаты вывода call Print_Word pop bx mov ax, bx ; выводим состояние push bx ; переключающих клавиш mov bx, 0306h call Print_Word pop bx jmp charin , Следующий байт находится в сегменте кода. , Он используется для демонстрации возникновения . исключения при попытке записи в сегмент кода wrongl db ? continue: , После нажатия на клавишу <ESC> выходим в это место программы. . Следующие несколько строк демонстрируют команды, которые , вызывают исключение. Вы можете попробовать их, если уберете . символ комментария из соответствующей строки. , Попытка записи за конец сегмента данных, Метка wrong . находится в самом конце программы mov [wrong], al , Попытка записи в сегмент кода. mov [wrongl], al 'ДИАЛОГ-МИФИ'
58 Защищённый режим процессоров Intel 80286/80386/80^86 ; Попытка извлечения из пустого стека ; pop ах ; Загрузка в сегментный регистр неправильного селектора. ; mov ах. 12B0h , mov as. ах , Прямой вызов исключения при помощи команды прерывания, int 1 call set_rmode , установка реального режима mov bh стираем экран и call clrscr ; выходим в DOS mov ah,4с int 21h END? start MACRO setgctentry mov [ldesc_struc bx) base_U,ax mov [(desc_struc bx).base_h),dl ENDM Установка защищенного режима PROC set_pmode NEAR mov ax.DGROUP mov dl,ah shr dl,4 shl ax,4 mov si,ax mov di,dx add ax,OFFSET gdtr adc dl,0 mov bx,OFFSET gdt_gdt setgdtentry ; Заполняем дескриптор в GDT, указывающий на дескрипторную таблицу прерываний mov ах,si . загружаем 24-битовый адрес сегмента mov dx,di данных add ах.OFFSET idt ; адрес дескриптора для IDT adc dl,0 mov bx,OFFSET gdt_idt setgdtentry , Заполняем структуру для загрузки регистра IDTR mov bx,OFFSET idtr mov [Gdtr_struc bx) idt_lj,ax mov [(idtr_struc bx).idt_h],dl mov bx,OFFSET gdt_ds mov ax,s i mov dx.di setgdtentry
Обработка прерываний в защищённом режиме 59 mov bx,OFFSET gdt_cs mov ax.cs mov dl,ah shr dl, 4 shl ax,4 setgdtentry mov bx,OFFSET gdt_ss mov ax,ss mov dl,ah shr dl,4 shl ax,4 setgdtentry готовим возврат в реальный режим push ds mov ax,40 mov ds,ax mov (WORD 67],OFFSET shutdown_return mov [WORD 69],cs pop ds cli mov al,8f out CMOS_PORT,al jmp dell dell: mov al,5 out CMOS_PORT+1,al mov ax,[rl_crt] ; сегмент видеопамяти mov es.ax call enable_a20 ; открываем линию A20 mov [real_ss],ss ; сохраняем сегментные mov [real_es],es ; регистры ----------- Перепрограммируем контроллер прерываний ------ , Устанавливаем для IRQ0-IRQ7 номера прерываний 20h-27h mov dx,MASTER8259A mov ah,20h call set_int_ctrlr , Устанавливаем для IRQ8-IRQ15 номера прерываний 28h-2Fh mov dx,SLAVE8259A mov ah,28h call set_int_ctrlr , Загружаем регистры IDTR и GDTR lidt [FWORD idtr) Igdt [QWORD gdt_gdt] . Переключаемся в защищенный режим mov ах,VIRTUAL_MODE lmsw ax i jmp far flush db 0ea dw OFFSET flush "ДИАЛОГ-МИФИ'
60 Защищённый режим процессоров Intel 80286/80386/80486 dw CS_DESCR LABEL ‘ flush FAR ; Загружаем селекторы в сегментные регистры mov ах,SS_DESCR mov ss,ax mov ax,DS_DESCR mov ds,ax ; Разрешаем прерывания sti ret ENDP set_pmode ; Возврат в реальный режим DATASEG ; Пустой дескриптор для выполнения возврата процессора ; в реальный режим через перевод его в состояние отключения. null_idt idt_struc о CODESEG PROC set_rmode NEAR mov [real_sp],sp ; Переводим процессор в состояние отключения, это эквивалентно , аппаратному сбросу, но выполняется быстрее. Сначала загружав» ; IDTR нулями, затем выдаем команду прерывания lidt [FWORD null_idt] int 3 ; Это старый способ сброса процессора через ; контроллер клавиатуры. ; mov al,SHUT_DOWN ; out STATUS_PORT,al rwait: hit jmp rwait LABEL shutdown_return FAR in al,INT_MASK_PORT and al,0 out INT_MASK_PORT.al mov ax,DGROUP mov ds,ax assume ds:DGROUP cli mov ss,[real_ss] mov sp,[real_sp] mov ax,000dh out CMOS_PORT,al sti mov es,[real_es] call disable_a20
Обработка прерываний в защищённом режиме 61 ret ENDP set_rmode ’ обработка исключений Обработчики исключений. Записываем в АХ номер исключения и передаем управление процедуре shutdown label exc_00 WORD label mov ax, 0 jmp shutdown exc_01 WORD label mov ax,l jmp shutdown exc_02 WORD LABEL mov ax, 2 jmp shutdown exc_03 WORD LABEL mov ax,3 jmp shutdown exc_04 WORD LABEL mov ax, 4 jmp shutdown exc_05 WORD LABEL mov ax, 5 > jmp shutdown exc_06 WORD LABEL mov ax,6 jmp shutdown exc_07 WORD LABEL mov ax, 7 jmp shutdown exc_00 WORD LABEL mov ax,8 jmp shutdown exc_09 WORD LABEL mov ax, 9 jmp shutdown exc_0A WORD LABEL mov ax.0ah jmp shutdown exc_0B WORD label mov ax,0bh jmp shutdown exc_0C WORD label mov ax,0ch jmp shutdown exc_0D WORD label mov ax,0dh jmp shutdown exc_0E WORD label mov ax,0eh jmp shutdown exc 0FWORD 'ДИАЛОГ-МИФИ'
62 Защищённый режим процессоров Intel 80286/80386/80486 mov ax,0fh jmp shutdown LABEL exc_10WORD mov ax,10h jmp shutdown LABEL exc_llWORD mov ax.llh jmp shutdown LABEL exe_12 WORD mov ax,12h jmp shutdown LABEL exc_13 WORD mov ax,13h jmp shutdown LABEL exc_14 WORD mov ax,14h jmp shutdown LABEL exc_15 WORD mov ax,15h jmp shutdown LABEL exc_16 WORD niov ax,16h jmp shutdown LABEL exc_17 WORD mov ax,17h jmp shutdown LABEL exc_18 WORD mov ax,18h imp shutdown LABEL exc_19 WORD mov ax,19h ' jmp shutdown LABEL exc_lA WORD mov ax.lah jmp shutdown LABEL exc_lBWORD mov ax,1bh jmp shutdown LABEL exc_lC WORD mov ax,Ich jmp shutdown LABEL exc_lD WORD mov ax.ldh jmp shutdown LABEL exc_lE WORD mov ax,leh jmp shutdown LABEL exc_lF WORD mov ax,1fh jmp shutdown DATASEG exc_msg db "Exception . . code Press any key.. CODESEG
Обработка прерываний в защищённом режиме 63 • вывод на экран номера исключения, кода ошибки, ' дампа регистров и возврат в реальный режим. ррОС shutdown NEAR call rdump ; дамп регистров процессора push ах call beep ; звуковой сигнал Выводим сообщение об исключении mov ax,[vir_crt] mov es,ax mov bx,ld mov ax,4 mov si,OFFSET exc_msg mov dh,74h mov ex, SIZE exc_msg call writexy pop- ax mov bx, 040bh ; номер исключения call Print_Word pop ax mov bx, 0420h ; код ошибки call Print_Word pop ax mov bx., 0416h ; смещение call Print_Word pop ax mov bx, 041Ih ; селектор call Print_Word call set_rmode ; возвращаемся в реальный режим mov ах, 0 ; ожидаем нажатия на клавишу int 16h mov bh, 07 h call clrscr mov ah,4Ch int 21h ENDP shutdown . Перепрограммирование контроллера прерываний . На входе: DX - порт контроллера прерывания АН - начальный номер прерывания PROC set int ctrlr NEAR mov al ,11 out dx, al jmp SHORT $+2 mov al, ah inc dx out dx, al 'ДИАЛОГ-МИФИ'
64 Защищённый режим процессоров Intel 80286/80386/80486 jmp mov out jmp SHORT $+2 al ,4 dx, al SHORT $+2 mov al , 1 out dx, al jmp SHORT $+2 mov al,0ff out dx, al dec dx ret ENDP set_ int ctrlr Разрешение линии А20 PROC enable_a20 NEAR mov al,A20_PORT out STATUS_PORT,al mov al,A20_ON out KBD_PORT_A,al ret ENDP enable_a20 Запрещение линии A20 PROC disable_a20 NEAR mov al,A20_PORT out STATUS_PORT,al mov al,A20_OFF out KBD_PORT_A,al ret ENDP disable_a20 Обработчик аппаратных прерываний IRQ2-IRQ7 PROC dummy_iret0 NEAR push ax ; Посылаем сигнал конца прерывания в первый контроллер 8259А mov al,EOI out MASTER8259A,al pop ax iret ENDP dummy_lret0 Обработчик аппаратных прерываний IRQ8-IRQ15 PROC dummy_iretl NEAT! push ax ; Посылаем сигнал конца прерывания в первый ; и второй контроллеры 8259А
Обработка прерываний в защищённом режиме 65 mov al.EOI out MASTER8259A,al out SLAVE8259A,al pop ax iret ENDP dummy_iretl ' Процедура выдает короткий звуковой сигнал PROC beep NEAR push ax bx ex in al,KBD_PORT_B push ax mov ex,80 beep0: push ex and al,11111100b out KBD_PORT_B,al mov ex,60 jdlel: loop idlel or al,00000010b idle2: or al,00000010b out KBD_PORT_B,al mov ex,60 ex, 60 loop idle2 pop ex loop beep0 pop ax out KBD_PORT_B,al pop ex bx ax ret ENDP beep Процедура задерживает выполнение программы на некоторое время, зависящее от быстродействия процессора. PROC pause NEAR push ex mov ex,10 ploop0: push ex xor ex.ex ploopl: loop ploopl pop ex loop ploop0 pop ex ret ENDP pause 'ДИАЛОГ-МИФИ'
66 Защищённый режим процессоров Intel 80286/80386/80486 Процедуры для работы с клавиатурой DATASEG key_flag db 0 key_code dw 0 ext_scan db 0 keyb_status dw 0 CODESEG ; Обработчик аппаратного прерывания клавиатуры PROC Keyb_int NEAR call beep , выдаем звуковой сигнал push ax mov al, [ext_scan] расширенный скан-код cmp al, 0 или обычный ? jz normal_scanl ; обработка расширенного кан-кода cmp al, 0elh ; это клавиша <Pause>? jz pause_key * in al, 60h ; вводим скан-код cmp al, 2ah ; игнорируем префикс 2Ah jz intkeyb_exi t_l cmp al, 0aah игнорируем отпускание jz intkeyb_exit_l клавиш mov ah, (ext_scan) записываем скан-код и call Keyb_PutQ расширенный скан-код в ’’очередь", состоящую из одного слова mov al, 0 сбрасываем признак mov [ext_scan], al получения расширенного jmp intkeyb_exit скан-кода pause_key обработка клавиши <Pause> in al, 60h вводим скан-код, cmp al, 0c5h если это код <Pause>, jz pause_keyl записываем его в очередь, cmp al', 45h иначе игнорируем jz pause_keyl jmp intkeyb_exit pause_keyl: mov ah, [ext_scanj запись в очередь call Keyb_PutQ кода клавиши <Pause> mov al, 0 сбрасываем признак mov [ext_scan], al получения расширенного jmp intkeyb_exit скан-кода , обработка обычного скан- -кода
Обработка прерываний в защищённом режиме 67 normal_scan1: in al, 60h , вводим скан-код crop al, 0feh ; игнорируем FEh jz intkeyb_exit cmp al, 0elh ; расширенный скан-код? jz ext_key если да, то на обработку ; расширенного скан-кода cmp al, 0e0h jnz normal_scan ext_key: mov [ext_scan], al ; устанавливаем признак jmp int'keyb_exit ; расширенного скан-кода Сброс признака расширенного скан-кода и выход intkeyb_exit_l: mov al, 0 mov [ext_scan], al jmp intkeyb_exit , Запись нормального скан-кода в очередь и выход normal_scan,: mov ah, 0 call Keyb_PutQ intkeyb_exit: in al, 61h ; разблокируем клавиатуру mov ah, al • or al, 80h out 61h, al xchg ah, al out 61h, al mov al,EOT , посылаем сигнал конца out MASTER8259A,al ; прерывания pop ax sti iret ENDP Keyb_int ; Запись скан-кода и расширенного скан-кода в , "буфер”, состоящий из одного слова. PROC Keyb_PutQ NEAR push ax mov [key_code], ax ; записываемый код ; Обрабатываем переключающие клавиши cmp ах, 002ah , L_SHIFT down jnz ©@kbl mov ax, [keyb_status] or ax, L.SHIFT mov (keyb_status], ax jmp keyb_putq_exit. @@kbl "ДИАЛОГ-МИФИ" 3
68 Защищённый режим процессоров Intel 80286/80386/80486 cmp ах, 00aah ; L_SHIFT up jnz @©kb2 mov ax, [keyb_status] and ax NL_SHTFT mov [keyb status], ax jmp 'keyb_putq_exit ©@kbi cmp ax, 0036h ; R_SHTFT down jnz @©kb3 mov axv, [keyb_statusJ or ax, R_SH1FT mov [keybjstatus], ax jmp Keyb_putq_exit @0kbo cmp ax. 00b6h ; R_SHIFT up jnz @@kb4 mov ax, Ikeyb_status] and ax. NR_SHIF1 mov [keyb_status], ax jmp keyb_putq_exit @0kb4: cmp ax, 001dh ; L_CTRL down jnz (9@kbJ’ mov ax, [ keyb .status ] or ax, L_CTRL. mov [keyb_status), ax jmp keyb_putq_ex.Lt @©Kb5: cmp ax. 009dh L_CTRL up jnz ©@kbn mov ax, [ keyb_.status J and ax, NL_CTRL mov [keyb_status], ax jmp keyb putq_exit ©©kb6 cmp ax 0e01dh ; R_CTRL down jnz ©©kb? mov ax, [ keyb..status ] or ax. R_CTRL mov [ keyb_stat,us ] , ax jmp keyb_putq_exit @©kb7: cmp ax, 0e09dh ; R_CTRL up jnz @©kb8 mov ax, [keyb_status1 and ax, NR_CTRL mov [keyb_3tatus], ax jmp keyb_putq_exit ©0kb8: cmp ax, 0038h ; L_ALT down jnz ©©kb9 mov ax, [keyb_statusj or ax, L_ALT mov [keyb. status], ax jmp keyb_putq_exit
Обработка прерываний в защищённом режиме 69 tag, к Ь9 Cinp ах, 00b8h L_ALT up jnz @Okbi0 mov ax, [keyb_status] and ax, NL_ALT mov [keyb_status1, ax jmp keyb_putq_exit @@kbl0: cmp ax, 0e038b ; R_ALT down jnz @@kbll mov ax, [keyb_status ] or ax, R_AlT mov (keyb_suauus], ax jmp keyb_p.itq_ex.it @@kbll cmp ax, 0e0b8h ; R_ALT up jnz @@kbl2 mov ax, lkeyb_statusJ and ax NR_ALT mov [keyb_status] ax j mp keyb_putq_exlt @@kbl2 . cmp ax, 003ah , CAPS_LOCK up jnz йекЫЗ mov ax, [keyb_status] xor ax, CAPS_IOCK mov [keyb_status] ax jmp keyb_putq_exit @@kbl3 cmp ax, 00bah ; CAPS_LOCK down jnz <a@kbi4 jmp keyb_putq_exit @@kt>14 cmp ax, 0046b , SCR_LOCK up jnz й@кЫ5 mov ax, [keyb_status) xor ax, SCR LOCK mov [keyb_status), ax jmp keyb_putq_exit @@kbl5 cmp ax, 00c6h , SCR LOCK down jnz @@kbl6 jinp keyb_put.q_exit @@kbl6 cmp ax, 0045h NUM_LOCK up jnz @@kbl7 mov ax, Ikeyb_status] xor ax, NUM_LOCK mov [keyb_status), ax jmp keyb_putq_exit @@kbl7. cmp ax, 00c5h , NUM_LOCK down jnz @@kbl8 jmp keyb_putq exit @@kbl8: 'АиАЛрг .мпфи •
70 Защищённый режим процессоров Intel 80236/80386/80486 Обработка прерываний в защищённом режиме 71 ax enp ах, 0e052h , INSERT up jnz @rakbL9 mov ах, [кеуb_status] xor ax, INSERT mov [keyt>_status] , jmp keyb_putq_exit (aekb.1 9 cmp ax, 0e0d2h jnz @@kb20 jmp keyb_putq_exit @@kb20 test ax, 0080b juz keyb_putq_exit mov al, 0ffh mov [key_flag], al keyb_putq_exit: pop ax ret ENDP Keyb_PutQ INSERT down ; фильтруем отжатия клавиш , устанавливаем признак ; готовности для чтения символа из буфера Программное прерывание, предназначенное для чтения символа , из буфера клавиатуры. По своим функциям напоминает преоывани INT 16h реального режима В АХ возвращается скан-код нажатой ; клавиши, в ВХ - состояние переключающих клавиш PROC Int_30h_Entfy NEAR push dx ; запрещаем прерывания.и cli ; сбрасываем признак mov al, 0 ; готовности скан-кода mov [key_f]ag], al , в буфере клавиатуры ; Ожидаем прихода прерывания от клавиатуры , Процедура клавиатурного прерывания установит , признак в переменной key flag keyb_int_wait: sti разрешаем прерывания пор ждем прерывание’ пор cli запрещаем прерывания • mov al, [key_flag] , и опрашиваем флаг cmp a 1, 0 готовности скан-кода jz keyb_int_wait mov a 1, 0 ; сбрасываем флаг mov [key_flag], al ; готовности mov ax, [key_ccde] ; записываем скан-код mov bx, Ikeyb_status) ; и состояние переключающих ; клавиш sti разрешаем прерывания pop dx iret ENDP Int_30h_Entry TIMER section DATASEG timer_cnt dw 0 CODESEG PROC Timef.int NEaR cli push ax Увеличиваем содержимое счетчика времени mov ах, [timer_cnt] inc ax mov [timer_cnt], ax Примерно раз в секунду выдаем звуковой сигнал test ах, 0fh jnz timer_exit call beep ti-ner_exit Посылаем команду конца прерывания mov al,EOI out MASTER8259A al pop ax sti iret ENDP Timer_int Процедуры оослуживания видеоконтроллера DA FASEG- columns db 80d rows db 25d rl_crt dw COLOR.SEG vi r_crt dw CRT_DESCR eurr_line dw 0d text buf db CODESEG Определение адреса видеопамяти PROC set_crt_base NEAR mov ax,40 mov es, ax mcv bx,[WORD es 4a) mcv [columns],bl mov bl,[BYTE es 84] inc bl mov [rows],bl mov bx,[WORD es.P0RT6845] cmp bx,COLOR_PORT 'ДИАЛОГ- МИФИ’
72 Защищённый режим процессоров Intel 80236/80386/30486 je color_crt mov [rl_crt),MONO_SEG mov [v i r_cг t j,MDA_DESCR color_crt: ret ENDP set_crt_base ; Запись строки в видеопамять PROC writexy NEAR push si push di mov dl,(columns] mul dl add ax,bx shl ax,l mov di,ax mov ah.dh write_loop: lodsb stosw loop write_loop pop di pop si ret ENDP writexy , Стирание экрана (в реальном режиме) PROC clrscr NEAR xor ex,ex mov dl,[columns ] mov dh,(rows) mov ax,0600 int 10 ret ENDP clrscr DATASEG t hello_msg db " Protected mode monitor "TINY/OS", v.1,1 for CPU 80286 | (C) Frolov AV., 1992 CODESEG ; Вывод начального сообщения в защищенном режиме PROC write_hello_msg NEAR mov ax,[vir_crt) mov es,ax mov si,OFFSET hello_msg mov bx,0 mov ax,[curr_line) inc [curr_line]
Обработка прерываний в защищённом режиме 73 mov cx.SIZE hello_msg mov dh,30h call writexy call beep ret ENDP write_hello_msg Процедура выводит на экран содержимое АХ (х,у) - (bh, bl) PROC Print_Word NEAR push ax push bx push dx push ax mov cl,8 rol ax,cl call Byte_to_hex mov [text_buf], dh mov [text_buf+l), dl pop ax call Byte_to_hex mov [text_buf+2], dh mov [text_buf+3], dl mov si, OFFSET text_buf mov dh, 70h mov ex, 4 mov al, bh mov ah, 0 mov bh, 0 call writexy pop dx pop bx pop ax ENDP Print_Word DATASEG tabl db ’0123456789ABCDEF' CODESEG Преобразование байта в шестнадцатеричный символьный формат al - входной байт dx - выходное слово PROC Byte_to_hex near push ex push bx mov bx, OFFSET tabl "ДИАЛОГ-МИФИ
74 Защищенный режим процессоров intel а0386/803об/8048(> push ax and al,0fh xlat mov dl, al- pop ax mov cl,4 shr al,cl xlat. mov dh al pop bx pop ex ret ENDP Byte_to_hex DATASEG reg_title db " CS IP AX BX CX DX SP EP SI DI sreg_title db " Ds' ES SS FLAGS CODESEG ; Вывод на экран содержимого регистров процессора PROC г dump NEaR pushf pusha mov di es mov ax (vir_crt) mov es,ax mov si.OFFSET reg title mov bx,1 ; (X.Y) - (AX.BX) mov ax.6 mov ex,SIZE reg_title mov dti.lfh ; черный на голубом фоне call writexy , Выводим содержимое всех регистров mov ах,es ; cs mov bx. 0702h call Frint_Word mov bp, sp mov ax, fbp+18d] ; ip mov bx, 0708h call Print_Wcrd mov bx. 070eh mov ax,[bp+14d] , ax call Print_Wcrd mov bx 0714b mov ax [bp+8d] , bx call Print Word
Обработка прерываний в защищённом режиме 75 mov mov cal 1 bx, 071 ah ax,[bp+12d] Print_Word ; ex mov bx, 0720h mov ax,[bp+10d] ; dx call Print_Word mov ax, bp add ax,20d sp mov bx, 0726h cal 1 Print_Word mov ax,[bp+4d] . bp mov bx, 072ch cal 1 Print_Word mov bx. 0732b mov ax.[bp+2] ; si call Print_Word mov bx 0738h mov ax. [ bp ] , di call Pnnt_Word mov si,OFFSET sreg _title mov bx,l mov ax, 8 mov ex,SIZE sreg title mov dh,Ifh call writexy mov bx, 0902h mov ax ds ; ds call Print_Word mov bx 0908h mov ax di ; es call Print_Word mov bx , 090eh mov ax, ss ; ss cal 1 Print_Word mov bx, 0914h mov ax, [bp+16d] , flags cal 1 Frint_Word , Восстанавливаем содержимое регистров рора popf ret ENDp rdump CSEG_SIZE = ($ - start) DATASEG dSEG_SIZE = ($ - DSEG_BEG) wpong db ? END start "ДИАЛОГ. МИФИ
Глава 4 МУЛЬТИЗАДАЧНОСТЬ В ПРОЦЕССОРЕ i80286 В подавляющем большинстве программы, составленные для реального режю процессора, выполняются в однозадачном режиме, полностью монополизир; все ресурсы компьютера. Однако в реальной жизни требуется одновременен доступ к двум или большему числу программ. Подтверждением этому служит наличие огромного количества резидентен программ - от простейших часов и калькуляторов до сложных резидентных инт грированных сред, аналогичных Borland SideKick. Резидентные программы, за редким исключением, не реализуют настоящу мультизадачность. Обычно с помощью резидентных программ вы можете толы переключаться от одной запущенной программы к другой. Типичный прим, ’’мультизадачной” резидентной программы - часы, которые работают параллел но с другими программами и постоянно показывают время в заранее опр делённом месте экрана. Другой пример - резидентная программа фоновой печа' PRINT, входящая в состав MS-DOS. Использование резидентных программ не самый лучший способ организащ переключения задач. Это связано с возникновением конфликтов между разли ными резидентными программами - например, по клавишам их активизации и. по используемым прерываниям. Учитывая необходимость реализации переключения программ, фир| Microsoft в операционной системе MS-DOS версии 5.0 реализовала переключ тель программ, встроенный в диалоговую оболочку DOSSHELL. Эта оболоч; позволяет запустить на выполнение несколько программ и переключаться от о, ной к другой. Но активна только одна задача - та, на которую переключил' пользователь. Остальные находятся в ’’замороженном” состоянии. Часто бывает необходимо, чтобы программы работали в режиме разделен! времени процессора. Тогда надо использовать операционную систему, работа» щую в мультизадачном режиме, - OS/2, UNIX, XENIX, WINDOWS, DeskView. Мультизадачность позволяет не только задействовать все ресурсы совреме! ных персональных компьютеров, но и существенно повышает производится ность труда. Например, с помощью модема принимается файл размером 2 Мбайта. Скорость передачи данных по телефонным линиям редко превыше 2400 бит в секунду, поэтому в худшем случае процесс получения файла мож растянуться на часы. Без использования мультизадачное™ компьютер всё э время будет занят только приёмом файла. Более того, в основном он будет нах литься в состоянии ожидания из-за медленной передачи данных. Без мультизадачности вы обречены ждать завершения процесса и не сможе выполнять на компьютере никакую другую работу, что само по себе весьма п чально. И это несмотря на то, что компьютер практически ничем не загружен!
Мультизадачность в процессоре i80286 77 Как же можно организовать мультизадачность? Самый простой способ заклю- чается в использовании таймера. Напомним, что таймер вырабатывает прерывание IRQO примерно 18,2 раза в секунду- Операционная система может использовать это прерывание для пере- ключения с одной выполняющейся программы на другую, предоставляя каждой программе квант времени. При этом у пользователя компьютера возникнет иллюзия параллельной работы нескольких программ. К сожалению, из-за ограниченного объёма книги мы не сможем подробно обсудить все проблемы, связанные с организацией мультизадачное™. В конце книги есть список литературы, в которой эти вопросы рассмотрены более подро- бно. Однако тем не менее остановимся на нескольких принципиальных моментах (которые напрямую не связаны с защищённым режимом работы процессора). Первый момент связан с загрузкой программ. В мультизадачной среде одно- временно работают несколько программ. Они должны либо все одновременно находиться в оперативной памяти, либо загружаться при необходимости с диска. Если программы загружены в память одновременно, то для каждой из них, ра- зумеется, должна быть выделена своя область памяти. Как для программ, так и для областей данных, принадлежащих этим программам. Для обеспечения надёжной работы программ было бы также неплохо изолиро- вать эти области памяти друг от друга для предотвращения случайного или пред- намеренного доступа за пределы выделенной области памяти. Второй момент - процесс переключения от выполнения одной программы к выполнению другой. Инициатором этого процесса обычно является таймер, гене- рирующий периодические прерывания. При переключении необходимо полностью сохранить контекст выполняемой программы, чтобы в дальнейшем можно было продолжить её выполнение с прер- ванного места. Под контекстом программы мы здесь понимаем содержимое реги- стров центрального процессора (а также регистров арифметического сопроцессо- ра, если он используется одновременно несколькими программами). Третий момент связан с необходимостью обеспечения взаимодействия па- раллельно работающих программ. Программы должны иметь возможность полу- чать доступ к аппаратным ресурсам компьютера, к сервису операционной систе- мы. Так же они должны уметь обмениваться друг с другом данными, сигнализи- ровать друг другу и операционной системе о возникновении каких-либо событий. При монопольном использовании компьютера в однозадачном режиме все ре- сурсы компьютера находятся во владении запущенной программы. Но если одно- временно работают несколько программ и все они хотят вывести что-нибудь на экран дисплея... Должен существовать механизм, обеспечивающий совместное использование ресурсов компьютера параллельно работающими программами. Ситуация напоминает железнодорожный переезд - движение разрешено либо поездам, либо автомобилям, но не одновременно и тем и другим! Решение проблемы также аналогичное - установка семафора. Только в случае с железной дорогой это настоящий семафор, а в случае мультизадачной операци- онной системы это ячейка памяти, отражающая текущее состояние ресурса - "ДИАЛОГ-МИФИ"
78 Защищённый режим процессоров Intel 80286/80386/80486 свободен или занят. Если ресурс компьютера занят какой-либо программой, дру- гие программы должны ждать, пока он не освободится (пока не проедет поезд). Нет никаких принципиальных препятствий для реализации мультизадачное™ в реальном режиме. Однако ограничения, присущие реальному режиму, не поз воляют сделать это достаточно эффективно. Например, ограниченное адресно, пространство не позволяет держать в оперативной памяти одновременно не., колько больших программ, а подгрузка программ с диска выполняется медление Отсутствие какой бы то ни было изоляции адресных пространств програ> влечёт за собой ненадёжную работу всей системы в целом, т. к. любая програи ма из-за ошибки или преднамеренно может разрушить всю систему. Поэтому все мультизадачные операционные системы используют защищённып режим работы процессора Адресация памяти в защищённом режиме полностью удовлетворяет требованиям изолирования параллельно работающих программ. Например, для каждой программы можно создать свою локальную таблиц дескрипторов LDT В этом случае программа принципиально будет иметь доступ только к своей области памяти, выделенной ей операционной системой. Для ор- ганизации межзадачного взаимодействия можно вызывать модули операционно.1 системой через вентили вызова. Кроме того, операционная система может соз дать области памяти "общего пользования’’, поместив соответствующие дескрип торы в глобальную таблицу дескрипторов GDT. Таблица GDT одна на все прог раммы и доступна всем программам Кроме того, процессор i80286 и более старшие модели имеют специалыш- средства, значительно ускоряющие переключение с одной программы на друт. за счёт автоматического сохранения контекста в специально выделенной для ка- ждой программы области памяти. В этой главе мы рассмотрим средства мультизадачное™ процессора i80286 и приведём пример небольшого мультизадачного монитора, обеспечивающего па- раллельную работу нескольких программ. Задача и сегмент состояния задачи До сих пор мы говорили о параллельной работе программ. На самом деле ка ждая отдельная программа может состоять из нескольких частей, работаюши параллельно. Например, текстовый процессор может содержать программные Ми дули которые параллельно с редактированием текста выполняют перенумер^ цию страниц, печать текста или автоматическое сохранение его на диске. Каж дую такую часть программы мы будем называть задачей Исходя из этой терминологии, в мультизадачной среде одновременно выпол няется много задач, принадлежащих разным программам. Причём количество за дач больше или равно количеству выполняющихся программ. Как правило, квантование времени процессора выполняется на уровне задач, г не на уровне программ. По прерыванию таймера процессор переключается oi одной задачи к другой, и таким образом осуществляется параллельное выполне- ние программ.
Мультизадачное™ в процессоре I80286 79 Для хранения контекста неактивной в настоящий момент задачи процессор i80286 использует специальную область памяти, называемую сегментом состоя- ния задачи TSS (Task State Segment). Формат TSS представлен на рис. 14. Лис. 14. Формат сегмента состояния задачи TSS Сегмент TSS адресуется процессором при- помощи 16-битного регистра TR (Task Register), содержащего селектор дескриптора TSS, находящегося в глобальной таблице де- скрипторов GDT (рис. 15). Поле доступа содержит бит В - бит заня- тости. Если задача активна, этот бит устана- вливается процессором в 1. Операционная система для каждой задачи создаёт свой TSS. Перед тем как переклю- читься на выполнение новой задачи, процес- сор сохраняет контекст старой задачи в её сегменте. TSS. Что же конкретно записывается в TSS при переключении задачи? Записывается содержимое регистров об- щего назначения АХ, BX, СХ, DX, регистров SP, BP, SI, D1, сегментных регистров ES, CS, SS, DS, содержимое указателя команд IP и регистра флажков FLAGS. Кроме того, сохраняется содержимое регистра LDTR, оп- ределяющего локальное адресное пространс- тво задачи. Дополнительно при переключении задачи в область TSS со смещением 44 операцион- ная сисгема может записать любую инфор- мацию, которая относится к данной задаче. Эта область процессором не считывается и не модифицируется. Поле Link представляет собой поле обратной связи и используется для органи- зации вложенных вызовов задач. Это поле мы рассмотрим в следующем разделе. Поля Stack 0, Stack 1, Stack 2 хранят логические адоеса (селекторхмещепие) отдельных для каждого кольца защиты стеков. Эти поля используются при меж- сегментных вызовах через вентили. Резерв Доступ Базовый адрес Предел „ 1в бит _ > 0 бит < > 24 бита 1в бит Поле доступа дескриптора TSS p|DPt |о|о|о|в|т| 7 6 5 И 321 О Рис. 15. Дескриптор сегмента состояния задачи TSS Jljiz обеспечения защиты данных процессор назначает отдельные стеки для каждого кольца защиты. Когда задача вызывает подпрограмму из другого кольца через вентиль ; вызова, процессор вначале загружает указатель стека "ДИАЛОГ-МИФИ*
80 Защищённый режим процессоров Intel 80286/80386/80486 SS:SP адресом нового стека, взятого из соответствующего поля TSS. Затем г но ый стек копируется содержимое регистров SS:SP задачи (т. е. ад рес вершины старого стека задачи). После этого в новый стек копируются пара- метры, количество которых задано в вентиле вызова, и адрес возврата. Таким образом, при вылове привилегированного модуля через вентиль вызоь менее привилегированная программа не может передать в стеке больше парамет- ров, чем это определено операционной системой для данного модуля. Включение адресов стеков в TSS позволяет разделить стеки задач и обеспечи- вает их автоматическое переключение при переключении задач. Переключение задач Для переключения задач имеются следующие возможности: переключение по команде JMP; переключение по команде. CALL; переключение по прерыванию. В первом и втором случаях для переключения задачи используются обычны, команды JMP и CALL, но в качестве операнда в этих командах указывается ад- рес сегмента TSS задачи, на которую необходимо переключиться Если произошло переключение с первой задачи на вторую при помощи кома нды JMP, то для возврата к выполнению первой задачи необходимо вновь ис- пользовать JMP, указав в качестве операнда адрес TSS первой задачи. Команда CALL позволяет организовать вызов вложенных задач. Переключив- шись из первой задачи на вторую, программа может вно«ь вернуться к первой задаче, если она выполнит команду IRET. В этом случае по команде IRET прои- зойдет обратное переключение задач. Адрес TSS для возврата команда IRET возьмёт из поля обратной связи Link текущего сегмента TSS, куда он был запи- сан командой CALL при первом переключении задач Кроме того, при переключении .задачи командой CALL в поле FLAGS сегмен- та TSS вызванной задачи устанавливается в 1 бит вложенной задачи NT. Коман- да JMP, если она использована для переключения задачи, сорасываст бит N'l Формат регистра флагов для процессоров i80386 и 180486 описан в приложе- нии 1. Регистр флагов FLAGS процессора i80286 - это младшее слово 32-разря/ него регистра EFLAGS. Аналогично тому, как можно вызвать подпрограмму через вентиль вызова для вызова задачи командой CALL можно использовать вентиль задачи. Формат вентиля задачи представлен на рис. 16. Поле доступа вентили задачи ГеТ^д~°|°|1 i°|ii 7 6 5 4 3 2 1 О Рис. 16. Вентиль задачи
Мультизадачное™ в процессоре i80286 81 Вентили задач, вызываемых по команде CALL, могут располагаться в табли- цах GDT или LDT. Обратите внимание на одно существенное различие между вызовом подпрог- раммы и вызовом задачи. После возврата из подпрограммы при её повторном вызове мы войдём в процедуру в начальной точке входа. В аналогичном случае при возврате из задачи и её повторном вызове управление будет передано кома- нде, находящейся сразу за командой IRET Это происходит потому, что при переключении задачи в сегменте TSS запи- сывается содержимое регистров CS:IP на момент переключения задачи. Если за- дача была вызвана при помощи команды CALL и возврат (обратное переключе- ние) был выполнен по команде IRET, в TSS записывается адрес CS:IP, указыва- ющий на следующую после IRET команду. Вы можете поместить там команду безусловного перехода JMP на начало задачи и таким образом зациклить задачу После этого вызов задачи станет похож на вызов подпрограммы. Существует ещё одна очень интересная возможность для переключения за- дач - переключение задач по прерыванию. Эту возможность можно легко реализовать, если поместить вентиль задачи в дескрипторную таблицу прерываний IDT. Например, можно сделать отдельные задачи для обработки исключений или аппаратных прерываний В последнем случае обработчикам аппаратных прерываний не нужно использовать стек при- кладных задач, т. к. они будут иметь свой собственный стек. Синхронизация задач и семафоры Прежде чем привести конкретный пример простейшей мультизадачной систе- мы, расскажем о применении семафоров как средств синхронизации задач. Как правило, любая мультизадачная операционная система содержит более или менее развитые средства синхронизации и взаимодействия задач. Семафоры как средство синхронизации задач предназначены для управления коллективным доступом со стороны задач к какому-либо ресурсу. Под ресурсом мы будем по- нимать не только физические ресурсы компьютера (диски, клавиатуру и т. д.), но и .логические ресурсы ячейки памяти, буфера и т. п. Программа, владеющая ресурсом или создавшая ресурс, может создать сема- фор для управления этим ресурсом. Физически семафор реализуется в оператив- ной памяти и представляет из себя ячейку памяти (достаточно одного байта или иногда даже одного бита памяти). В простейшем случае для семафора определяются операции: создание семафора; уничтожение семафора; сброс семафопа; ожидание, пока семафор не будет установлен. 'ДИАЛОГ-МИФИ"
82 Защищённый режим процессоров Intel 80286/80386/80486 Эти операции выполняются операционной системой по запросам лрикладны: программ В примере мультизадачной программы, приведённой ниже в этой гл] ве, мы должны сами реализовать все семафорные операции. Что касается двух первых операций, то мы выбрани самое простое решени< Семафоры создаются статически на этапе трансляции программы и представляю из себя простые статические переменные. Операция уничтожения семафора этом случае не используется, т, к. мы создаём все нужные нам семафоры ш трансляции программы. Операции сброса и установки семафора заключаются в записи соответственн нуля и единицы в ячейке памяти, распределённую семафору. Единственная о,. бенность выполнения этих операций заключается в том, что они должны ( . непрерываемыми, т е. на время выполнения этих операций необходимо зап,- тить переключение задач. Так как в нашем случае задачи переключаются п прерываниям таймера, мы на время выполнения операций сброса и установки се мафора запрещаем все прерывания при помощи команды CLI. Операция ожидания установки семафора, напротив, должна выполняться с ра зрешёнными прерываниями, т. к. семафор ожидает одна задача, а его установи выполняет другая задача. Однако в процессе ожидания необходимо считать сод{ ржимое Семафора и проверить ею состояние, и воз эта операция должна вып'ш пяться с запрещёнными прерываниями. Пример мультизадачного монитора Для того, чтобы вы могли почувствовать мультизадачность, мы подготовит пример программы, реализующей параллельную работу нескольких задач в pi жиме разделения времени. Эта программа состоит из нескольких модулей, составленных на языках ас, мблера и Си Первые два файла предназначены для определения используемых констант структур данных. Листинг 4. Определение констант и структур для модулей, составленных языке ассемблера, , Файл t.os . inc CMOS PORT equ 70h PORT_6845 equ o3h COLOR_PORT equ 3d4h MONOJPORT equ 3b4h STATUS_PORT equ 64h SHUT_DOWN equ 0feh INT_MASK_PORT equ 21h VIRTUAL_MODE equ 0001 A20_PORT equ 0dlh A20_ON equ 0ofh A 20 OFF equ 0ddh
Мультизадачность в процессоре i80286 83 EOl equ 20h ^srER8^!A equ 20h SLAVE8259A equ 0a0h equ 60h КВГ'_Р°НТ-В equ 61h L SHI?" equ 0000000000000001b NL SHIFT equ 1111111111111110b R SHIFT equ 0000000000000010b NR SHIFT equ 1111111111111101b L CTFl equ 0000000000000100b NL CTRL equ 1111111111111011b p_CTRL equ 0000000000001000b NR. CTRL equ 1111111111110111b L ALT equ 0000000000010000b nl.alt equ 1111111111101111b R ALT equ 0000000000100000b NR_ALT equ 1111111111011111b CAPS LOCK equ 0000000001000000b SQR_LOCK equ 0000000010000000b NUM LOCK equ 0000000100000000b INSERT equ 0000001000000000b STRUC idtr _stru( idt-len dw 0 idt_low dw 0 idt .hi db 0 rsrv db 0 ENDS idtr_struc Листинг 5. Определение констант и структур для модулей, составленных на языке Си , Файл t ,os. h *define word unsigned int // Селекторы, определенные в GDT *def ine #define CODE-SELECTOR DATA_SELECTOR 0x08 0X10 // // сегмент кода сегмент данных #define #define #define TASK-l-SELECTOR TASK_2_SELECTOR MaIN_TASK_SELECTOR 0x18 0x20 0x28 / / задача TASK_1 задача TASK_2 главная задача ^define #def ine VID MEM_SELECTOR IDT-SELECTOR 0x30 0x38 // сегмент видеопамяти таблица IDT #'def ine ^define KEYBIN TASK-SELECTOR KEYB_TASK.SELECTOR 0X40 0x48 // задача ввода с клавиатуры задача обработки *def me FLIP TASK SELECTOR 0x50 // клавиатурного прерывания задача FLIP__TASK // Байт typedef доступа struct ( unsigned accessed : 1; 'ДИАЛОГ-МИФИ'
84 Защищённый ражим процессоров Intel 80286/80386/80486 unsigned read_write : 1; unsigned conf_exp : 1; unsigned code : 1; unsigned xsystem : 1; unsigned dpi : 2; unsigned present : 1; } ACCESS; // Структура дескриптора typedef struct descriptor [ word limit; word base_lo; unsigned char base_hi; unsigned char type_dpl; unsigned reserved; } descriptor; // Структура вентиля вызова, задачи, прерывания, исключения typedef struct gate { word offset; word selector; unsigned char count; unsigned char type_dpl, word reserved; ) gate; // Структура сегмента состояния задачи TSS typedef struct tss ( word link; // поле обратной связи word word sp0; ss0; // указатель стека кольца 0 word word spl; ssl; // указатель стека кольца 1 word word sp2; ss2, // указатель стека^кольца 1 word word word word word word word word word word word word word word word ) tss; ip; f1ags; ax; ex; dx; bx; sp; bp; si; di; es; cs; ss; ds; Idtr; // регистры процессора // Размеры сегментов и структур tfdefine TSS_SIZE (sizeof(tss)) #define DESCRIPTOR_SIZE (sizeof(descriptor))
Мультизаданность в процессоре i80286 85 #define GATE_SIZE (sizeof(gate)) ^define IDT_SIZE (sizeof(idt)) // Физические адреса видеопамяти для цветного // и монохромного видеоадаптеров ^define COLOR_VID_MEM 0xb8000L ^define MONO_VID_MEM 0xb0000L // Видеорежимы #define MONO_MODE 0x07 // монохромный #define BW_80_MODE 0x02 // монохромный, 80 символов #define COLOR_80_MODE 0x03 // цветной, 80 символов // Значения для поля доступа ^define TYPE_CODE_DESCR 0x18 #define TYPE_DATA_DESCR 0x10 #define TYPE_TSS_DESCR 0x01 #define TYPE_CALL_GATE 0x04 #define TYPE_TASK_GATE 0x85 tfdefine TYPE_INTERRUPT_GATE 0x86 ^define TYPE_TRAP_GATE 0x87 #define SEG_WRITABLE 0x02 #define SEGJREADABLE 0x02 tfdefine SEG_PRESENT_BIT 0x80 // Константы для обработки аппаратных прерываний tfdefine EOI 0x20 #define MASTER8259A 0x20 tfdefine SLAVE8259A 0xa0 // Макро для формирования физического адреса из компонент // сегментного адреса и смещения tfdefine MK_LIN_ADDR(seg,off) (((unsigned long)(seg))< <4) + (word)(off) // Тип указателя на функцию типа void без параметров typedef void (func_ptr)(void); Файл tos.c (листинг 6) содержит основную программу, которая инициализиру- ет процессор для работы в защищённом режиме и запускает все задачи. С помо- щью функции с названием Init_And_Protected_Mode_Entry () мы попадаем в за- щищённый режим и выводим сообщение на экран о том, что в главной задаче установлен защищённый режим. Регистр TR загружается селектором главной за- дачи при помощи функции load_task_register(). Сразу после этого программа переключается на выполнение задачи TASK_1. Эта задача просто выводит сообщение о своём запуске на экран и возвращает управление главной задаче. Цель этой процедуры - продемонстрировать процесс переключения задач с помощью команды JMP. После возврата в главную задачу программа размаскирует прерывания от кла- виатуры и таймера. Остальные задачи, определённые при инициализации систе- мы, оживают, когда начинают поступать и обрабатываться прерывания таймера. Начиная с этого момента главная задача разделяет процессорное время нарав- не с остальными задачами. Что же она делает? 'ДИАЛОГ-МИФИ'
86 Защищённый режим процессоров Intel 80286/80386/80486 Главная задача сбрасывает семафор с номером 0, вслед за чем ожидает его установку. Этот семафор устанавливается задачей, которая занимается вводом символов с клавиатуры и выводит на экран скан-коды клавиш, а также состоя- ние переключающих клавиш. Как только окажется нажатой клавиша ESC, зада- ча ввода символов с клавиатуры устанавливает семафор 0, что и приводит к за- вершению работы главной задачи. Перед завершением работы главная задача устанавливает реальный режим ра- боты процессора, стирает экран и возвращает управление операционной системе. Листинг 6. Программа мультизадачного монитора. ; Файл tos.с #include <stdio.h> #include <stdlib.h> #include <dos.h> tfinclude <conio.h> #include "tosh” // Определения вызываемых функций void Init_And_Protected_Mode_Entry(void); void protected_mode(unsigned long gdt_ptr, unsigned int gdt_size, word cseg, word dseg); word load_task_register(word tss_selector); void real_mode(void); void jump_to_task(word tss_selector); void load_idtr(unsigned long idt_ptr, word idt_size); void Keyb_int(void); void Timer_int(void); void Int_30h_Entry(void); extern word kb_getch(void), void enable_interrupt(void); void taskl(void); void task2(void); void flipflop_task(void); void keyb_task(void); void init_tss(tss "t, word cs, word ds, unsigned char ‘sp, func_ptr ip); void init_gdt_descnptor(descriptor 'descr, unsigned long base, word limit, unsigned char type), void exception_0(void); //{ prg_abort(0); } void exception_l(void); //{ prg_abort(1); } void exception_2(void); //{ prg_abort(2); ) void exception_3(void); //( prg_abort(3); ) void exception_4(void), //{ prg_abort(4); ) void exception_5(void); //{ prg_abort(5); }
Мультизадачность в процессоре i80286 87 void exception_6(void); //[ prg_abort(6); ) void exception_7(void); //( prg_abort(7); ) void exception_8(void); //( prg_abort(8); ) void exception_9(void); //( prg._abort(9), 1 void exception_A(void); //( prg_abort(0xA); ) void exception_B(void); //( prg_abort(0xB); ) void exception_C(void); //{ prg_abort(0xC); ) void exception_D(void); //{ prg_abort(0xD); ) void exception_E(void), //( prg_abort(0xE); j void exception_F(void); //{ prg_abort(0xF); ) void exception_10(void); //{ prg_abort(0xl0); ) void exceptional (void); //{ prg_abort(0xll ) ; ) void exception_12(void); //( prg_abort(0xl2); ) void exception_13(void); //( prg_abort(0xl3); j void exception_14(void); //( prg_abort(0xl4); ) void exception_15(void); //( prg_abort(0xl5); j void exception_16(void); //( prg_abort(0xl6); ) void exception_17(void); //( prg_abort(0xl7); j void exception_18(void); //( prg_abort(0xl8); 1 void exception_19(void); //{ prg_abort(0xl9); ) void exception_lA(void); //{ prg_abort(0xlA), ] void exception_lB(void), //( prg_abort(0xlB); i void exception_lC(void); //{ prg_abort(0xlC); j void exception_lD(void); //{ prg2abort(0xlD); } void exception_lE(void); //( prg_abort(0xlE); ) void exception_lF(void); //( prg_abort(0xlF); ) void iret0(void); void iretl(void); //---------------------------------------- // Глобальная таблица дескрипторов GDT //---------------------------------------- descriptor gdt{ll]; //---------------------------------------- // Дескрипторная таблица прерываний IDT gate idt[] = ( // Обработчики исключений { (word)<6exception_0, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, //0 ( (word)<£exception_l, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //1 { (word)<£exception_2, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //2 { (word)4exception_3, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //3 { (word)&exception_4, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 },' // 4 ( (word).£exception_5, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //5 ( (word)&exception_6, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 6 ( (word)fiexception_7, CODE_SELECTOR, 0, 'ДИАДОГ-МИФИ'
88 Защищённый режим процессоров Intel 80286/80386/80486 TYPE_TRAP_GATE, 0 ), //7 { (word)<£exception_8, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //8 ( (word)<fiexception_9, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //9 ( (word)<6exception_A, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, //A { (word)<6exception_B, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), // В ( (word)<6exception_C, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ) , // C { (word)<6exception_D, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // D { (word)<£exception_E, CODE SELECTOR, 0, TYPE_TRAP_GATE, 0 T, // E [ (word)<6exception_F, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), // F { (word)&exception_10, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //10 { (word)&exception_ll, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, //11 ( (word)<Sexception_12, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), // 12 ( (word)<Sexception_13, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, //13 ( (word)<fiexception_14, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //14 ( (word)&exception_15, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //15 ( (word)ifiexception_16, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //16 { (word)<£exception_17, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, //17 { (word)<Sexception_18, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //18 { (word)&exception_19, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //19 { (word)<fiexception_lA, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), // 1A ( (word)<£exception_lB, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ). //IB { (word)<6exception_lC, CODTYPE_SELECTOR. 0, TYPE_TRAP_GATE, 0 ), // 1C ( (word)&exception_lD, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //ID I ( (word)&exception_lE, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //IE ( (word)&exception_lF, CODTYPE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //IF // Обработчик прерываний таймера { (word)<£Tinier_int, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, //20 // Вентиль задачи, запускающейся по прерыванию от клавиатуры
Мультизадачность в процессоре i80286 89 ( 0, KEYB_TASK_SELECTOR, 0, TYPE_TASK_GATE, 0 ), //21 // Заглушки для остальных аппаратных прерываний ( (word)<£iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, //22 { (word)<Siret0. CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), //23 { (word)<Siret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), //24 { (word)*iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), //25 ( (word)£iret0, CODE_SELECTOR. 0, TYPE_INTERRUPT_GATE, 0 ), //26 ( (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), //27 ( (word)fiiretl, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), //28 ( (word)&iretl, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), //29 ( (word)&iretl, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 1, // 2A ( (word)cfiiretl, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), // 2B ( (word)£iretl, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), // 2C { (word )<£i ret 1, CODE_SELECTOR , 0, TYPE_INTERRUPT_GATE, 0 ), //2D { (word )<£i ret 1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), // 2E ( (word)4iret 1, CODE_SELECTOR, 0. TYPE_INTERRUPT_GATE, 0 ), // 2F // Обработчик для программного прерывания, которое // используется для ввода с клавиатуры { (word)<6Int_30h_Entry, CODE SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 T, //30 // Вентиль задачи FLIP_TASK { 0, FLIP_TASK_SELECTOR, 0, TYPE_TASK_GATE, 0 ) //31 ). // Сегменты TSS для различных задач tss main_tss; // TSS главной задачи tss task_l_tss; // TSS задачи TASK_1 tss task_2_tss; // TSS задачи TASK_2 tss keyb_task_tss; // TSS задач обслуживания tss keyb_tss; // клавиатуры tss flipflop_tss, // TSS задачи FLIP_TASK ^/ Стеки для задач unsigned char task_l_stack[1024), unsigned char task_2_stack[1024j; ’Аиалог-мифи’
90 Защищённый ражим процессоров Intel N0286/80386/80486 unsigned char keyb.task.stackl1024], unsigned char keyb_stack[ 1024'] , unsigned char flipflop_stack[1024]; word y=0. // номер текущей строки для вывода на экран // Начало программы void main(void) { // Стираем экран textcolor(BLACK); texobackgrouna(LIGHTGRAY). clrscrO; // Входим в защищенный режим Init_And^Protected_Mode_ Entryt ) ; // Выводим сообщение vi_hello_msg(), У-3; vi_print(0 у++ " Установлен защищенный режим в главной задаче”, 0x7f) // Загружаем регистр TR селектором главной задачи // т 6 задачи mainO load_task_register(MATN_TASK_SELE’CTOR); // Переключаемся на задачу 7ASK.1 j nmp_to_task(TASK.1.SELECTOR); // После возврата в главную задачу выдаем сообщение vi_print(0. у++ Вернулись в главную задачу”, 0x7f), у++; // Запускаем планировщик задаи vi_print(0. у++ ,” Запущен планировщик задач”, 0x70). enable_interrupt(), // разрешаем прерывание таймера // Ожидаем установки семафора с номером 0 После того, // как этот семафор окажется установлен, возвращаемся // в реальный режим. // Семафор 0 устанавливается задачей, обрабатывающей ввод // с клавиатуры которая работает независимо от главной задаче vi_print(0, у++ , " Для возврата в реальный режим нажмите ESC", 0x70); sem.clear(0); // сброс семафора 0 sem_wait(0); // ожидание установки семафора 0 // Возврат в реальный режим, стирание экрана // и передача управления MS-DOS real_mode() ; textcolor(WHITE), textbackground(BLACK), clrscrO, // Функция инициализации сегмента TSS //---------------------------------------- void init_tss(tss ‘t, word cs, word ds, unsigned char 'sp,, func.ptr ip)
Мультизадачное™ в процессоре i80286 91 t->cs = cs; // селектор сегмента кода t->ds = ds; // поля ds, es, ss устанавливаем t->es = ds; // на сегмент данных t->ss = ds; t->ip = (word)ip; // указатель команд t->sp = (word)sp; // смещение стека t->bp = (word)sp; ) // Функция инициализации дескриптора в таблице GDT void init_gdt_descriptor(descriptor "descr, unsigned long base, word limit, unsigned char type) ( // Младшее слово базового адреса descr->base_lo = (word)base; // Старший байт базового адреса descr->base_hi = (unsigned char)(base >> 16); // Поле доступа дескриптора descr->type_dpl = type; // Предел descr->limit = limit; // Зарезервированное поле, должно быть сброшено в 0 descr->reserved = 0; ) //---------------------------------------------------------- // Инициализация всех таблиц и вход в защищенный режим void Init_And_Protected_Mode_Entry(void) union REGS r; // Инициализируем таблицу GDT, элементы с 1 по 5 init_gdt_descriptor(<figdt(11, MK_LIN_ADDR(_CS, 0), 0xffffL, TYPE_CODE_DESCR | SEG_PRESENT_BIT | SEG_READABLE); init_gdt_descriptor(figdt[2), MK_LIN_ADDR(_DS, 0), 0xffffL, TYPE_DATA_DESCR | SEG_PRESENT_BIT [ SEG_WRITABLE); init_gdt_descriptor(<Sgdt[3], MK_LIN_ADDR(_DS, <Stask_l_tss) , (unsigned long)TSS_SIZE-l, TYPE_TSS_DESCR | SEG_PRESENT_BIT); init_gdt_descriptor(&gdt[4] , MK_LIN_ADDR(_DS, <Stask_2_tss), (unsigned long)TSS_SIZE-l, TYPE_TSS_DESCR | SEG_PRtSENT_BIT); init_gdt_descriptor(&gdt[5], MK_LIN_ADDR(_DS, &main_tss), (unsigned long)TSS_SIZE-l, TYPE_TSS_DESCR I SEG_PRESENT_BIT); 'ДИАЛОГ-МИФИ'
92 Защищённый режим процессоров Intel 80286/80386/80486 // Инициализируем TSS для задач TASK_1, TASK_2 init_tss(<fitask_l_tss, CODE-SELECTOR, DATA_SELECTOR, task_l_stack+sizeof(task_l_stack), taskl); init_tss(&task_2_tss, CODE-SELECTOR, DATA_SELECTOR, task_2_stack+sizeof(task_2_stack), task2); // Инициализируем элемент 6 таблицы GDT - // дескриптор для сегмента видеопамяти // Определяем видеорежим г.h.ah=15; int86(0xl0,iSr.fir) ; // Инициализация для монохромного режима i f (г. h. al=MONO_MODE) init_gdt_descriptor(&gdt[6}, MONO_VIDMEM, 3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT T SEG_WRITABLE); // Инициализация для цветного режима else if(r.h.al = BW_80_MODE || r.h.al = COLOR_80_MODE) init_gdt_descriptor(&gdt[6], COLOR_VID_MEM, 3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); else ( printf(”\nH3BHHHTe, этот видеорежим недопустим,”); exit(-l); ) // Инициализация элементов 7 и 8 таблицы GDT init_gdt_descriptor(<6gdt [ 7 1, MK_LIN_ADDR(_DS, fiidt), (unsigned long)IDT_SIZE-l, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE), init_gdt_descriptor(&gdt[8], MK_LIN_ADDR(_DS, .6keyb_task_tss), (unsigned long)TSS_SIZE-l, TYPE_TSS_DESCR | SEG_PRESENT—BIT); // Инициализация TSS для задачи KEYB_TASK init_tss(<£keyb_task_tss, CODE-SELECTOR, DATA_SELECTOR, keyb_task_stack+sizeof(keyb_task_stack), keyb_task); // Инициализация элемента 9 таблицы GDT init_gdt_descriptor(<figdt[9], MK_LIN_ADDR(_DS, &keyb_tss), (unsigned long)TSS_SIZE-l, TYPE—TSS—DESCR j SEG_PRESENT—BIT); // Инициализация TSS для задачи KEYB обработки ввода // с клавиатуры init_tss(<fikeyb_tss. CODE-SELECTOR, DATA_SELECTOR, keyb_stack+sizeof(keyb_stack), Keyb_int); // Инициализация элемента 10 таблицы GDT init_gdt_descriptor(<6gdt( 101 , MK_LIN_ADDR(_DS, &f1ipflop_tss), (unsigned long)TSS_SIZE-l, TYPE—TSS—DESCR | SEG_PRESENT_BIT); /7 Инициализация TSS для задачи FLIP_TASK init_tss(&flipflop_tss, CODE-SELECTOR, DATA_SELECTOR, flipflop_stack+sizeof(flipflop_stack), flipflop_task);
Мультизадачность в процессоре i80286 93 // загрузка регистра IDTR load_idtr(MK_LIN_ADDR(_DS, &idt), IDTJSIZE), // Вход в защищенный режим protected_raode(MK_LIN_ADDR(_DS, &gdt), sizeof(gdt), CODE_SELECTOR, DATAJSELECTOR); ) файл tasks.c содержит тексты программ, которые будут работать в режиме разделения времени (кроме задачи TASK.1; она запускается только один раз). Задача TASK_1 (процедура taskl) выдаёт сообщение о своём запуске и пере- даёт управление главной задаче. Задача TASK_2 (процедура task2) попеременно выводит на экран строки "FLIP” и "FLOP”, переключая попутно семафор с номером 1. Задача FLIP_TASK (процедура flipflop_task) также попеременно выводит на экран строки ’’FLIP" и "FLOP", но только тогда, когда семафор с номером 1 ус- тановлен. Таким образом, задача TASK_2 управляет работой задачи FLIP_TASK. Задача KEYB_TASK (процедура keyb_task) вводит символы с клавиатуры и выводит скан-коды нажатых клавиш, а также состояние переключающих кла- виш. Как только оказывается нажатой клавиша ESC, задача устанавливает сема- фор с номером 0, что приводит к завершению работы главной задачи (ожидаю- щей установки этого семафора). Листинг 7. Задачи, которые будут работать параллельно. ; Файл tasks.с ♦include <stdio.h> ♦include <dos.h> ♦include <conio.h> ♦include <stdlib.h> ♦include "tos.h” word dispatcher!void); // Номер текущей строки для вывода на экран extern unsigned int у; // Задача TASK_1 void taskl(void) ( whiled) { vi_print(0,y++,” Запущена задача TASK_1, ” ’’переходим к главной задаче", 0x70); jump_to_task(MAIN_TASK_SELECTOR); Z/ После повторного запуска этой задачи снова входим в цикл. ) 1 77 Задача TASK_2 *°rd flipflopl = 0; ‘ong delay_cntl = 01; ‘ЛИАЛОГ-МИФИ‘
94 Защищённый режим процессоров Intel 80286/80386/80486 void task2(void) { while(l){ // Периодически выводим на экран строки FLIP/FLOP, каждый раз // переключая семафор номер 1. Этот семафор однозначно // соответствует выведенной на экран строке. asm sti if(delay_cntl > 1500001 ) { asm cli if(flipflopl) { vi_print(73,3," FLIP ”, 0x4f); sem_clear(l); ) else [ vi_print(73,3,” FLOP ”, 0xlf); sem_set(l); ] flipflopl ’= 1; delay_cntl = 01; asm sti ) delay_cntl++, } ) word flipflop = 0; long delay_cnt =01; void flipflop_task(void) { // Эта задача также периодически выводит на экран строки // FLIP/FLOP, но выводит строкой выше и с меньшим периодом // Кроме того, эта задача работает только тогда, когда // установлен семафор номер 1. wh11е(1) ( asm sti if (delay__cnt > 200001 ) ( sem_wait(l); // ожидаем установки семафора asm cli if(flipflop) vi_print(73,2,” FLIP ”, 0x20), else vi_print(73,2,” FLOP ”, 0x20); flipflop ’= 1, delay_cnt = 01; asm sti } delay_cnt++; ) ) word keyb_code; extern word keyb_status, void keyb_task(void) { // Эта задача вводит символы с клавиатуры и отображает // скан-коды нажатых клавиш и состояние переключающих клавиш // на экране. Если нажимается клавиша ESC, задача устанавлива // семафор номер 0. Работающая параллельно главная задача
Мультизадачность в процессоре i80286 95 // ожидает установку этого семафора. Как только семафор 0 // окажется установлен,’ главная задача завершает свою работу и // программа возвращает процессор в реальный режим, затем // передает управление MS-DOS. vi_print(60, 5, ’’ Key code: .... ”, 0x20); vi_print(60, 6, " Key status: ", 0x20); while(l) [ keyb_code = kb_getch(); vi_put_word(73, 5, keyb_code, 0x4f); vi_put_word(73, 6, keyb_status, 0x4f); if((keyb code & 0x00ff) — 1) sem set(0); } ) Файл semaphore содержит исходные тексты процедур сброса семафора, уста- новки семафора и ожидания семафора. В массиве semaphore [5] определено пять семафоров. Разумеется, что, когда вы будете экспериментировать с программой, вы можете изменить количество доступных семафоров. Листинг 8. Процедуры для работы с семафорами. , Файл semaphor.с «include <stdio.h> «include <dos.h> «include <conio.h> «include <stdlib.h> «include "tosh” // Массив из пяти семафоров word semaphore!5]; // Процедура сброса семафора. // Параметр sem - номер сбрасываемого семафора void sem_clear(int sem) ( asm cli semaphore[sem] - 0; asm sti } Zz Процедура установки семафора Z/ Параметр sem - номер устанавливаемого семафора void sem_set(int sem) ( asm cli semaphorefsem) - 1; j asm sti Z/ Ожидание установки семафора z/ Параметр sem - номер ожидаемого семафора v°id sem_wait(int sem) [ while(l) [ asm cli if(semaphore[sem]) break; // проверяем семафор '^НАЛОГ-МИФИ'
96 Защищённый режим процессоров Intel 80286/80386/80486 asm sti // ожидаем установки семафора asm пор asm пор ) asm sti ) Файл timer.c содержит обработчик аппаратного прерывания таймера, кот»| периодически выдаёт звуковой сигнал и инициирует работу диспетчера 3aj Диспетчер задач циклически перебирает селекторы TSS задач, участвующи процессе разделения времени, возвращая селектор той задачи, которая дол: стать активной. В самом конце обработки аппаратного прерывания таймера п исходит переключение именно на эту задачу. Листинг 9. Процедуры для работы с таймером и диспетчер задач. ; Файл timer.c ♦include <stdio.h> ♦include <dos h> ♦include <conio.h> ♦include <stdlib.h> ♦include "tosh" // Модуль обслуживания таймера ♦define EOI 0x20 ♦define MASTER8259A 0x20 extern void beep(void); exterh void flipflop_task(void); void Timer_int(void); word dispatcher(void); word timer_cnt, // Обработчик аппаратного прерывания таймера //------------------------------------------------------ void Timer_int(void) ( asm pop bp // Периодически выдаем звуковой сигнал timer_cnt += 1; if((timer_cnt & 0xf) = 0xf) beep(); // Выдаем в контроллер команду конца прерывания asm mov al,EOI asm out MASTER8259A,al // Переключаемся на следующую задачу, селектор TSS которой // получаем от диспетчера задач dispatcher() jump_to_task(dispatcher()); asm iret
Мультизадачность в процессоре i80286 97 // Диспетчер задач //---------------------------------------- // массив селекторов, указывающих на TSS // задач, участвующих в параллельной работе, // т е. диспетчеризуемых задач word task_list(] = ( MAIN_TASK_SELECTOR, FLIP_TASK_SELECTOR, KEYBIN_TASK_SELECTOR, TASK_2_SELECT0R ); word current_task = 0; // текущая задача word max_task = 3; // количество задач - 1 // Используем простейший алгоритм диспетчеризации - // выполняем последовательное переключение на все // задачи, селекторы TSS которых находятся // в массиве task_list[). word dispatcher(void) ( if(current_task < max_task) current_task++; else current_task « 0; return(task_list[current_task]); ) Для сокращения объёма и без того сложной программы мы не стали делать функционально полную обработку исключений, ограничившись простым аварий- ным завершением работы программы с выдачей номера исключения. Исходные тексты обработчиков исключений находятся в файле except.c. Листинг 10. Обработка исключений. Файл except.с ^include <stdio.h> ^include <dos.h> #include <conio.h> ^include <stdlib.h> ^include "tos.h” void prg_abort(int err); 7/ Номер текущей строки для вывода на экран extern unsigned int у; z/ Обработчики исключений Void exception_0(void) v°id exception_l(void) void exception_2(void) void exception_3(void) void exception_4(void) void exception_5(void) Void exception_6(void) "ДИАЛОГ-МИФИ’ ( prg_abort(0); } { prg_abort(1); ) { prg_abort(2); ) ( prg_abort(3); ] ( prg_abort(4); ) { prg_abort(5); } { prg_abort(6); }
98 Защищённый режим процессоров Intel 80286/80386/80486 void exception 7(void) prg abort(7); } void exception 8(void) prg abort(8); I void exception 9(void) prg abort(9); j void exception A(void) prg abort<0x8); ) void exception Bivoid> prg abort(0xB) J void exception C(void) prg abort(0xC); ) void exception E(void) prg abort(0xD); } void exception E(void) prg abort(0xE); ) void exception F(void) prg aoort(0xF); } void exception lE(vcid) prg abort(0xl0); } void exception ll(void) prg abort(0x)1) ; j void exception 12(void) prg abort(0xl2), } void exception 13(void) prg abort(0x13), ) void exception 14(void) prg abort(0xl4) , j vo id exception 15(void) prg аоогс(их15), } void exception 16(vcid) prg abort(0x16); ) void exception 17(void) prg abort(0x17) . ) void exception 18(void) prg abort(0xlb), ) void exception 19(void) prg abort(0x!9), ) void exception lA(void) prg abort(0xlA); l void exception JBtvuid) prg abort(0xlB), j void exception lC(void) prg abort(0xlC), } void exception ID(void) prg abort(0xiD) ) void exception lEtvoid) prg aoort(0xlE), ) void exception_lF(void) prg_abort(0xlF); ) // — // Аварийный выход из программы //---------------------------------- void prg_abort(int err) { vi_print(l,y++,"I 11---------> Произошло исключение”, 0xc)' rc-ai_mode(); // Возвращаемся в реальный режим // В реальном режиме выводим сообщение об исключении gotoxyd, ++у); cprinti(" Исключение %Х, нажмите любую клавишу” err); getch(), textcolor(WHITE); textbackground(BLACK), clrscr(); exit(0); ) В файле intproc.c расположены заглушки для гех аппаратных прерываний, работка которых сводится к простой посылке кода конца препывания в соотв твуюший контроллер прерывания. Листинг 11, Заглушки для аппаратных прерываний Файл intproc с #include <-stdio h> #include <dcs h>
Мулътизадачность в процессоре i80286 99 ^include <conio.h> ^include <stdlib.h> ^include "tos.h” // Заглушки для необрабатываемых аппаратных прерываний. void iret0(void) ( // первый контроллер прерываний asm [ push ах mov al,EOT out MASTER8259A,al pop ax pop bp iret ) ’ ) void iretl(void) ( // второй контроллер прерываний asm { push ax mov al.EOI out MASTER8259A,al out SLAVE8259A,al pop ax pop bp iret ) ) Файл keyb.c содержит простой интерфейс для вызова программного прерыва- ния int 30h, обеспечивающего ввод с клавиатуры. Листинг 12. Ввод символа с клавиатуры. ; Файл keyb.с «include «include «include «include «include <stdio.h> <dos. h> <conio.h> <stdlib.h> ’’tos.h” extern word key_code, // Функция, ожидающая нажатия любой // клавиши и возвращающая ее скан-код unsigned int kb_getch(void) { asm int 30h retiirn(key_code); Обработчик аппаратного прерывания клавиатуры мы взяли практически без изменений из программы, представленной в предыдущей главе. Исходные тексты находятся в файле keyboard.asm. 'ДИАЛОГ-МИФИ'
тио Защищённый режим процессоров Intel 80286/80386/80486 Листинг 13. Процедуры для работы с клавиатурой Файл keyboard asm IDEAL MODEL SMALL RADIX 16 P286 include "tos inc” Модуль обслуживания клавиатуры PUBLIC _Ktyb_int, _Int 30h Entry, _key_code, keyb_status EXTRN _beep PROC DATASEG _key_flag db 0 _key_code dw 0 ext_scan db 0 _kcyb.status dw 0 CODESEG FROC _Kcyb_int HEAR cl i call _beep push ax mov al, [ext_scan] cmp al, 0 jz normal_scanl cmp al, 0elh jz pause_key in al, 60h cmp al, 2ah jz intkeyb_exit_l cmp a 1. 0aah jz inlkeyb_.exit_l mov ah, lext_scan] call Keyb_PutQ mov al, 0 mov [ext_scan] al jmp intkeyb_exit pause_key in al, 60h cmp al, 0c5h jz pause.key1 cmp al, 45h jz pause^keyl jmp intkeyb_exit
Мультизадачность в процессоре i80286 101 pause_keyl: mov ah, [ext_scan] call Keyb_PutQ mov al, 0 mov [ext_scan], al jmp intkeyb_exit normal_scanl: in al, 60h cmp al, 0feh jz intkeyb_exit cmp al, 0elh j z ext_key cmp al, 0e0h jnz normal_scan ext_key: mov [ext_scan], al jmp intkeyb_exit intkeyb_exit_l: mov al, 0 mov [ext_scan], al jmp intkeyb_exit normal_scan: mov ah, 0 call Keyb_PutQ intkeyb_exit: in al, 61h mov ah, al or al, 80h out 61h, al xchg ah, al out 61h, al mov al.EOI out MASTER8259A,al pop ax sti iret jmp _Keyb_int ENDP _Keyb_int PROC Keyb_PutQ NEAR push ax c<np ax, 002ah ; L_SHIFT down jnz @©kbl mov ax, [_keyb_status] or ax, L_SHIFT mov [_keyb_status), ax jmp keyb_putq_exit @@kbl: cmp ax, 00aah ; L_SHIFT up jnz @@kb2 mov ax, [_keyb_status] and ax, NL_SHIFT 'ДИАЛОГ-МИФИ
102 Защищённый режим процессоров Intel 80286/80386/80486 mov jmp @©kb2: , cmp jnz mov or mov jmp @@kb3: \ cmp jnz mov and mov jmp @©kb4: [_keyb_status], ax keyb_putq_exit ax, 0036h ; R_SHIFT down ©@kb3 ax, [_keyb_status) ax, R_SHIFT (_keyb_status1, ax keyb_putq_exi t ax, 00b6h ; R_SHIFT up @@kb4 ax, [_keyb_status] ax, NRJSHIFT [_keyb_status], ax keyb_putq_exit cmp jnz mov or mov jmp @©kb5: ax, 001dh ; L_CTRL down @@kb5 ax, [_keyb_status] ax, L_CTRL [_keyb_status], ax keyb_putq_,exit cmp jnz mov and mov jmp ©@kb6: ax, 009dh ; L_CTRL up ©@kb6 ax, [_keyb_status] ax, NL_CTRL [_keyb_status], ax keyb_putq_exit cmp jnz mov or mov jmp @@kb7: ax, 0e01dh ; R_CTRL down @©kb7 ax, [_keyb_status] ax, R_CTRL (_keyb_status1, ax keyb_putq_exit cmp jnz mov and mov jmp @©kb8: ax, 0e09dh ; R_CTRL up @@kb8 ax, [_keyb_status] ax, NR_CTRL (_keyb_status], ax key b_pu tq_ex it cmp jnz mov or mov jmp ©@kb9: ax, 0038h ; L_ALT down @@kb9 ax, (_keyb_status] ax, L_ALT [_keyb_status1, ax keyb_putq_ex1t cmp jnz mov ax, 00b8h ; L_ALT up @@kbl0 ax, (_keyb_status1
Мультизадачность в процессоре i80286 103 and ах, NL_ALT mov [_keyb_status], ах jmp keyb_putq_exit @@kbl0: cmp ax, 0e038h ; R_ALT down jnz ©@kbll mov ax, [_keyb_status] or ax, R_ALT mov [_keyb_status], ax jmp keyb_putq_exit @@kbll: cmp ax, 0e0b8h ; R_ALT up jnz @@kbl2 mov ax, [_keyb_status] and ax, NR_ALT mov [_keyb_status], ax jmp keyb_putq_exit @@kbl2: cmp ax, 003ah ; CAPS_LOCK up jnz @@kbl3 mov ax, (_keyb_status] xor ax, CAPS_LOCK mov [_keyb_status], ax jmp keyb_putq_exit @@kbl3: cmp ax, 00bah , CAPS_LOCK down jnz @@kbl4 jmp keyb_putq_exit @@kbl4: cmp ax, 0046h ; SCR_LOCK up jnz @©kbl5 mov ax, [_keyb_status] xor ax, SCR_LOCK mov [_keyb_status], ax jmp keyb_putq_exit @®kbl5: cmp ax, 00c6h ; SCR_LOCK down jnz @@kbl6 jmp keyb_putq_exit @@kbl6: Cmp ax, 0045h ; NUM_LOCK up jnz @@kbl7 mov ax, (_keyb_status] xor ax, NUM_LOCK mov [_keyb_status], ax jmp keyb_putq_exit @@kb!7: cmp ax, 00c5h ; NUM_LOCK down jnz @©kbl8 jmp keyb_putq_exit @@kb!8: cmp ax, 0e052h ; INSERT up jnz @@kbl9 mov ax, [_keyb_status] xor ax, INSERT "ДИАЛОГ-МИФИ'
104 Защищённый режим процессоров Intel 80286/80386/80486 mov {_keyb_status], ах jmp keyb_putq_exit @@кЫ9 : cmp ax, 0e0d2h ; INSERT down jnz @@kb20 jmp keyb_putq_exit @@kb20 test ax, 0080h jnz keyb_putq_exit mov [_key_code], ax mov al, 0ffh mov (_key_flag], al keyb_putq_exit: pop ax ENDP Keyb_PutQ , Обработчик программного прерывания для ввода с клавиатуры. ; По своим функциям напоминает прерывание INT 16 ; реального режима. PROC _Int_30h_Entry NEAR push ax dx ; Ожидаем прерывание от клавиатуры keyb_int_wait: sti nop nop cli ; Проверяем флаг, который устанавливается ; обработчиком аппаратного прерывания клавиатуры mov al, [_key_flag] cmp al, 0 jz keyb_int_wait ; Сбрасываем флаг после прихода прерывания mov al, 0 mov [_key_flag], al sti pop dx ax iret ENDP _Int_30h_Entry END Файл screen.c содержит процедуры, необходимые для вывода информации i экран дисплея. Работа этих процедур основана на непосредственной записи да ных в видеопамять. Листинг 14. Процедуры для работы с видеоадаптером. ; Файл screen.c #include <stdio.h> #include <dos.h>
Мультизадачность в процессоре i80286 105 /include <conio.h> /include <stdlib.h> /include "tos.h” void vi_putch(unsigned int x, unsigned int y, char c, char attr); char hex_tabl(j = "0123456789ABCDEF"; // Вывод байта на экран, координаты (х,у), // выводится шестнадцатеричное представление // байта chr с экранными атрибутами attr void vi_put_byte(unsigned int x, unsigned int y, unsigned char chr, char attr) ( unsigned char temp; temp = hex_tabl((chr & 0xf0) >> 4]; vi_putch(x, y, temp, attr); temp = hex_tabl[chr & 0xf ] , vi_putch(x+l, y, temp, attr); ) // Вывод слова на экран, координаты (х,у), // выводится шестнадцатеричное представление // слова chr с экранными атрибутами attr. void vi_put_word(unsigned int x, unsigned int y, word chr, char attr) ( vi_put_byte(x, y, (chr & 0xff00) >> 8, attr); vi_put_byte(x+2, y, chr & 0xff, attr); ) // Вывод символа с на экран, координаты - (х,у), // атрибут выводимого символа - attr void vi_putch(unsigned int.x, unsigned int у .char c, char attr) ( register unsigned int offset; char far "vid_ptr; offset=(y"160) + (x’2); vid_ptr=MK_FP(VID_MEM_SELECTOR, offset); 'vid_ptr++=c; "vid_ptr=attr; // Вывод строки s на экран, координаты - (х,у), // атрибут выводимой строки - attr void vi_print(unsigned int x. unsigned int у, char "s, char attr) { ( while(’s) vi_putch(x++, y, 's++, attr), z/ Вывод стоки сообщения о запуске программы void vi_hello_msg(void) ( vi_print(0, 0, ” Protected mode monitor ’TINY/OS', ” "v.1.2 for CPU 80286 | (C) Frolov A.V., 1992 ”, 0x30); 'ДИАЛОГ-МИФИ'
106 Защищённый режим процессоров Intel 80286/8^388/80486 Последний файл - tossys'.asm - содержит уже знакомые вам процедуры для входа в защищённый режим и возврата обратно в реальный режим. Обратите внимание на процедуры _load_task_register и _jump_to_.task, выполняющие соот- ветственно загрузку регистра задачи TR и переключение на другую задачу. Листинг 15. Процедуры для инициализации, перехода в защищённый режим и возврата в реальный режим, для загрузки регистра TR и переключения задач. , Файл tossyst asm IDEAL MODEL SMALL RADIX lb P286 DATASEG include ”tos inc” PUBLIC .beep , Область памяти для инициализации IDTR idtr idtr_struc <,,,0> ; Область памяти для инициализации GDTR gdt_ptr dw (B‘15)-l , размер GDT 15 элементов gdt_ptr2 dw ? gdt ,ptr4 dw 7 ; Область памяти для записи селектора задачи, , на которую будет происходить переключение new_task dw 00h new select dw 00h Область памяти для хранения регистров используется для возврата в реальный режим real_ss dw ? real_sp dw ? reul_es dw ? protect_sel dw ? init tss dw ? CODESEG PUBL1С _real_mode,._protected_mode,_jump_to_task PUBLIC _load_tasK_register, _load_idtr. _enable_interrup , Процедура для переключения в защищенный режим ; Прототип для вызова , void protected_mode(unsigned long gdt_ptr, , unsigned int gdt_size, unsigned int cseg, unsigned int dser PROC _protected_mode NEAR push bp mov bp,sp . Параметр gdt_ptr
Мультизадачное™, в процессоре i80286 107 mov ax,[bp+4] ; мл. слово адреса GDT mov dx.lbp+6] ; ст слово адреса GDT mov [gdt_ptr4], dx ; запоминаем адрес GDT mov [gdt_ptr2], ax , Параметр gdt_size mov ax,[bp+8] ; получаем размер GDT mov [gdt_ptr], ax ; и запоминаем его ; Параметры cseg и dseg mov ax,[bp+10d] ; получаем селектор сегмента кода mov dx,[bp+12d] ; получаем селектор сегмента данных mov [св:p_mode_select), ах ; запоминаем для команды mov (protect_sel],•dx ; перехода far jmp , Подготовка к возврату в реальный режим push ds ; готовим адрес возврата mov ax,40h ; из защищенного режима mov ds,ах mov {WORD 67h],OFFSET shutdown_return mov [WORD 69h j, cs pop ds , Запрещаем и маскируем все прерывания cl i in al, INT_MASK_PORT and al, 0ffh out INT_MASK_PORT, al , Записываем код возврата в CMOS-память mov al,8f out CMOS_PORT,al jmp delay! delay! : mov al,5 out CMOS_PORT+1,al call enable_a20 ; открываем линию A20 mov [real_ss],ss ; запоминаем регистры SS и ES mov [real_es],es . Перепрограммируем контроллер прерываний , для работы в защищенном режиме mov dx,MASTER8259A mov ah,20 call set_int_ctrIr mov dx,SLAVE8259A mov ah, 28 call set_int_ctrlr . Загружаем регистры IDTR и GDTR lidt [FWORD idtr] lgdt [QWORD gdt_ptr] mov ax, 0001h ; переключаем процессор Imsw ax ; в защищенный режим jmp far flush db 0eah ‘ДИАЛОГ-МИФИ'
108 Защищённый режим процессоров Intel 80286/80386/80486 dw OFFSET flush p_mode_select dw LABEL flush FAR mov dx, [protect_selI mov ss, dx mov ds, dx mov es, dx ; Обнуляем содержимое регистра LDTR mov ах, 0 lldt ах pop bp ret ENDP _protected_mode ; Возврат fe реальный режим ; Прототип для вызова void real_mode(); PROC _real_mode NEAR ; Сброс процессора cli mov [real_sp], sp mov al, SHUT_DOWN out STATUS_PORT, al rmode_wait' hit jmp rmode_wait LABEL shutdown_return FAR Вернулись в реальный режим mov ax. DGROUP mov ds, ax assume ds-DGROUP mov ss,[real_ss] mov sp,[real_sp j in al, INT_MASK_PORT and al, 0 out INT_MASK_PORT, al call disable_a20 mov ax, DGROUP mov d s, ax mov ss, ax mov es, ax mov ax,000dh out CMOS_PORT,al sti ret ENDP rea] I mode
Мульч изадачность в процессоре i80286 109 Загрузка регистра TR. Прототип для вызова void load_task_registertunsigned int tss_selector): pFOC _load_task_register NEAR push bp mov bp,sp Itr [bp+4 ] ; селектор для текущей задачи pop bp ret ENPP _load_task_register Переключение на задачу Прототип для вызова void jump_to_task(unsigned int tss_selector); PROC _jump_to_task NEAR push bp mov bp.sp mcv ax,[bp+4] получаем селектор новой задачи mov [new_select),ax , запоминаем его jmp [DWORD iiew_task] , переключаемся на ; новую задачу pop bp ret ENDP _juhip_to_task Открываем линию A20 PROd enable_a20 NEAR push ax mov al. A20_PORT out STaTUS_PORT, al mov al, A20_ON out K.BD_PORT_A, al pop ax ret ENDP enable_a20 . Закрываем линию A20 f’ROC disable_a20 NEAP push ax mov al, A20_PORT out STATUS_POPT, al mov a] ,A20_OFF out KBD_PORT_A, al pop ax tNijp disable_a20 ‘ОЦА.ПОГ МИФИ'
110 Защищённый режим процессоров into! 80286/80386/80486 Готовим структуру для загрузки регистра IDTR Прототип для вызова функции void load_idtr(unsigned long idt_ptr, word idt_size), PROC _load_ldtr NEAR push bp mov bp.sp mov ax,fbp+4] ; мл слове адреса IDT mov dx,[bpt-6] ; ст слово адреса IDT mov bx, OFFSET idtr ; Запоминаем адрес IDTR в структуре mov [(idtr_struc bx) idt low], ax mov [(idtrstruc bx) idt_hi] 11 , Получаем предел IDT и запоминаем его в структуре mov ах, ibp+8] mcv [(idtr_struc bx) idt_len] ax pop bp ret ENDP _load_idtr Установка контроллера прерываний PROC set_int_ctrlr NEAR mov al, 11 out dx, al jmp SHORT $+2 mov al, ah inc dx out dx . al jmp SHORT $+2 mov al . 4 out dx, al jmp SHORT $+2 mov al , 1 out dx, al jmp SHORT $+2 mov al, 0ffh out dx, al dec dx ret ENDP set int ctrlr Выдача звукового сигнала PROC _beep NEAR push ax bx ex in al,KBD_PORT_B push ax mov ex 80
Мультизадачное^ а процессоре i80286 111 реер0: push сх and al,11111100b out KBD_PORT_B,al mov ex,60 idlel: loop idlel or al,00000010b out KBD_PORT_B,al mov ex,60 idle2: loop idle2 pop ex loop beep0 pop ax out KBD_PORT_B,al pop ex bx ax ret ENDP _beep Задержка выполнения программы PROC _pause NEAR push ex mov ex,10 ploop0: push ex xor# ex,ex ploopl: loop ploopl pop ex loop ploop0 pop ex ret ENDP _pause Размаскирование прерываний PROC _enable_interrupt NEAR in al, INT_MASK_PORT and al, 0fch out INT_MASK_PORT, al sti ret ENDP _enable_interrupt end ‘ДИАЛОГ-МИФИ
Глава 5 ОСОБЕННОСТИ ПРОЦЕССОРОВ i80386 и i80486 Появление следующей после i80286 модели процессора фирмы Intel - пронес сора i80386 предопределило конец эры использования средними и некоторым] большими организациями крупных компьютеров класса IBM-360/370 (аналога ми которых являются широко распространённые в нашей стране ЭВМ серю ЕС). По своим возможностям персональные компьютеры, выполненные на баз, процессора i80386, сопоставимы, а в ряде случаев превосходят ЭВМ серии ЕС И это ещё без учёта потребительских свойств и затрат на ремонт и обслужива ние. Последняя на момент написания данной книги модель - процессор 180484 обладает ещё большей производительностью. Несмотря на значительные архитектурные отличия по сравнению с процесса рами i8086 и i80286, процессоры i80386 и 180486 обеспечивают полную совмес тимость с программным обеспечением, разработанным для более ранних моделЫ процессоров. Процессор i80386 выполняет все программы, составленные дл: процессора 18086, и притом делает это значительно быстрее, чем сам 18086. К сожалению, часто владельцы такой мощной техники, как персональны! компьютеры на базе i80386 и i80486, не используют возможностей этих компью теров даже наполовину. Работая в среде операционной системы MS-DOS с прог раммами, подготовленными специально для этой операционной системы, вы бу дете использовать только режим совместимости процессоров i80386 и i8O486, ос тальные преимущества новых процессоров (помимо более высокой скорости вы полнения программ) будут вам недоступны. Аналогичное можно сказать об операционной системе OS/2 версий от 1.0 Д| 1.3. Она рассчитана на процессор i80286. Разумеется, вы можете использовав OS/2 этих версий в компьютерах на базе i80386 или 180486, однако лучше при обрести OS/2 версии 2.0 или более старшей версии, ориентированной на исполь зование архитектурных особенностей новых процессоров. Какие преимущества имеют процессоры i80386 и 180486 перед предыдущим моделями? Приведём только самые важные особенности новых процессоров: . Высокое быстродействие, определяемое, в частности, высокой тактово! частотой (25 МГц, 33 МГц и даже больше). Разрядность процессоров i80386 и 180486 составляет 32 бита (предыдуцш модели от 18086 до i80286 - 16-разрядными). Увеличение разрядност! процессора приводит к увеличению скорости выполнения программ (про цессор способен за один машинный такт обработать больше информации), Расширенный набор машинных команд и большое количество поддержи ваемых процессором типов данных позволяют создавать более эффектии ные, более компактные программы, которые работают значительно бысТ рее ориентированных на 16-разрядные процессоры.
Особенности процессоров i80386 и /80486 113 Новый механизм преобразования адресов, являющийся дальнейшим раз- витием механизма, использованного в процессоре i80286. Теперь процес- сор может рассматривать память как один или несколько сегментов, причём размер сегмента может достигать 4 Гбайт (4*2*30 байт). С другой стороны, страничная адресация позволяет организовать защиту памяти для каждой страницы. Размер страницы составляет 4 Кбайта. Использование страниц значительно облегчает реализацию виртуальной памяти. Помимо реального и защищённого режима работы в процессорах i80386 и 180486 предусмотрен режим виртуального процессора 8086 (виртуальный режим), в который процессор может войти из защищённого режима. Вир- туальный режим позволяет эмулировать процессор «8086, находясь в за- щищённом режиме. Это, в частности, даёт возможность в мультизадачной операционной системе организовать одновременное выполнение несколь- ких программ, ориентированных на процессор 18086. Объём книги ограничен, поэтому мы не сможем подробно рассмотреть все особенности процессоров 180836 и 180486. Для полного описания потребовалось бы много сотен страниц. Но это и не является нашей целью. Все подробности при необходимости вы сможете узнать из литературы, список которой приведён в конце книги. Однако для практического использования многих преимуществ новых процессоров вам не потребуются подробные знания всех особенностей. Это связано с тем, что реально вы будете работать в среде мультизадачной операционной системы или использовать иное программное обеспечение, кото- рое окажет вам значительную помощь в составлении программ для защищённого режима. Если же ваша область интересов связана с разработкой операционных систем защищённого режима для процессоров i80386 или 180486, вам не обой- тись без толстых руководств по процессорам, поставляемых фирмой Intel. Итак, мы сконцентрируем внимание на практическом использовании самых важных особенностей процессора 180836. И первое, с чего мы начнём, - это ме- ханизм преобразования адресов в процессоре 180836. Преобразование адресов Процессор i80386 в защищённом режиме использует трёхступенчатую схему преобразования адреса. Программы используют логический адрес, состоящий из селектора и смещения (аналогично процессору i80286). Селектор полностью аналогичен используемо- му в процессоре i80286. Компонента смещения является 32-разрядной, т. к. до- пустимый размер сегмента значительно превышает 64 Кбайта. Уровень логического адреса - это первая ступень в схеме преобразования ад- ресов. Вторая ступень - получение из логического адреса 32-разрядного линейного адреса. Линейный адрес берётся из глобальной или локальной таблицы дескрип- торов (GDT или LDT) в зависимости от соответствующего бита селектора (бит 2). Механизм получения линейного адреса напоминает механизм получения •ДИАЛОГ-МИФИ"
114 Защищённый режим процессоров Intel 80286/80386/80486 24-разрядного физического адреса в процессоре i80286. Однако линейный адр< не отображается непосредственно.на адресную шину памяти, т. е. он не являете физическим адресом. Для получения из линейного адреса физического адреса используется треп ступень - механизм страничной адресации. С помощью этого механизма 20 стар- ших бит линейного адреса используются для выбора блока памяти размером 4 Кбайта. Такой блок называется страницей физической памяти. Оставшиеся 12 бит линейного адреса представляют собой смещение внутри страницы. Проиллюстрируем процесс преобразования логического адреса в линейный (рис. 17). Рис. 17. Преобразование логического адреса в линейный Значение из поля индекса селектора используется в качестве индекса в табли- це LDT или GDT для выборки 32-разрядного базового адреса. Этот базовый адрес складывается со второй компонентой логического адреса - смещением. В результате получается 32-разрядный линейный адрес. ' Преобразование линейного адреса в физический иллюстрируется рис. 18. Рис 1&. Преобразование линейного адреса в физический
Особенности процессоров i80386 и 180486 115 Процесс вычисления адреса страницы часто называют трансляцией страниц. Старшие 10 бит линейного адреса используются как индекс в таблице, называе- мой каталогом таблиц страниц. Расположение каталога таблиц страниц в физиче- ской памяти определяется содержимым системного регистра процессора CR3. Каталог таблиц страниц содержит дескрипторы таблиц страниц, определяющие физический адрес таблиц страниц. В каталоге всего может быть 1024 дескрипто- ра. Самих же каталогов может быть сколько угодно, -но в каждый момент време- ни используется только один - тот, на который указывает регистр CR3. Следующие 10 бит линейного адреса предназначены для индексации таблицы страниц, выбранной с помощью старших 10 бит адреса Таблица страниц содер- жит 1024 дескриптора, определяющих физические адреса страниц памяти. Раз- мер одной страницы составляет 4 Кбайта, т. е. 4096 байт. Младшие 12 бит линейного адреса указывают смещение к адресуемому байту внутри страницы. На рис. 19 представлен формат дескриптора таблицы страниц. 31 12 11-0 В-7 в 6 4-3 2 1 0 < ддраскагталогатаблицстраииц | AVI | О | О| А| о |u|w|P~] Рис. 19. Дескриптор таблицы страниц Для представления старших 20 битов физического адреса таблицы сраниц в дескрипторе используются биты 12 - 31. Младшие 12 битов адреса таблицы всегда равны нулю, таким образом, таблица страниц должна быть выравнена в памяти на границу 4096 байт (на границу страницы;. Формат дескриптора страницы представлен на рис. 20. 31 12 111 ВТ 4 6 4-3 3 1 0 | Адр^сгжВлицыСТрачмц | AVL | О | О | А [ 0 | U |w |Р | Рис. 20. Дескриптор страницы Биты 12-31 в дескрипторе страниц указывают старшие 20 бит физического адреса страницы Младшие 12 бит адреса страницы всегда равны нулю. Назначение бит 0-11 одинаково и для дескриптора таблицы страниц, и для дескриптора страницы. В табл. 5 приведено описание этих бит. Таблица 5. Биты 0-12 дескрипторов таблиц страниц и страниц Номер бита Назначение 0 (Р) Бит присутствия в памяти. Установлен в 1, если определяемая данным дескриптором таблица страниц находится в оперативной памяти. Этот бит используется для организации виртуальной памяти 1 (W) Разрешение записи. Если бит установлен в 1, то запись в страницы разрешена. Бит используется для организации защиты от записи на уровне страниц 'ДИАЛОГ-МИФИ'
116 Защищённый режим процессоров Intel 80286/80386/80486 2 (U) Пользователь/супервизор. Используется для разграничения доступ к страницам операционной системы (страницы супервизора) и страницам программ пользователя. Значение бита, равное О, соответствует страницам супервизора, I ^страницам программы пользователя 3-4 Эти биты зарезервированы и должны быть установлены в 0 для совместимости со следующими моделями процессора 5 (А) Бит доступа. Он устанавливается процессором перед выполнением операций чтения страницы или записи в страницу 6 (D) Бит мусора. Устанавливается, если была выполнена запись в каталог или страницу 7-8 Эти биты зарезервированы и должны быть установлены в 0 для совместимости со следующими моделями процессора 9-12 (AVL) Эти биты доступны для использования операционной системой (AVL - Available for use) Мы видим, что для процесора i80386 добавилось ещё два типа таблиц, сод< ржащих дескрипторы и соответственно два типа дескрипторов - дескрипто таблиц страниц и дескриптор страниц. Для использования механизма трансляции страниц операционная система дол жна установить в 1 старший бит системного регистра CR0. Если этот бит не уста новлен в 1, физический адрес будет равен линейному, содержимое регистр адреса каталога таблиц страниц CR3 при этом для преобразования адрес использоваться не будет. Форматы дескрипторов, располагающихся в таблицах GDT, LDT и IDT, пре терпели изменения по сравнению с используемыми в процессоре i80286. Напри- мер, вместо 24-битового физического адреса в дескрипторах должен находиться 32-битовый линейный адрес. Напомним, что в дескрипторах процессора i80286 было зарезервировано два байта. Эти байты используются процессором i80386 (рис. 21). Рис. 21. Дескрипторы для процессора i80386 Процессор i80386 использует 32-разрядный базовый адрес сегмента и 20-раз- рядное поле предела. В зарезервированном для процессора i80286 поле в битах
Особенности процессоров i80386 и 180486 117 24-31 находится старший байт 32-разряднего базового адреса сегмента, Биты 16-19 используются для хранения старших четырех битов предела. В процессоре i80286 поле предела указывало размер сегмента в байтах. Для процессора 180486 интерпретация поля предела зависит от установки бита G - бита гранулярности. Если бит G установлен в 1, поле предела содержит размер сегмента в страницах (размером 4096 байт). Если бит С сброшен, размер сегмен- та вычисляется в байтах. Бит гранулярности G также находится в поле, которое в процессоре i80286 был" отмечено как зарезервированное. Поле обозначенное на рис. 21 как X, указывает разрядность выполняемых команд, принятых по умолчанию Если этот бит установлен в 1, используются 32 разрядные команды, если сброшен в 0 - 16-разрядные. Бит AVL используется системным программным обеспечением. Бит S - признак системного сегмента. Если этот бит сброшен в 0, то сегмент системный. Назначение остальных полей дескриптора аналогично используемому в про- цессоре i80286. В первой главе мы привели таблицу типов сегментов, в ней опи- саны и сегменты для процессора i80386. Обраоотка прерываний Процессор i80386 в защищённом режиме обрабатывает прерывания точно так- же, как и процессор i80286 Есть отличия в формате дескрипторов, располагаю- щихся в дескрипторной таблице прерываний IDT. Эти отличия заключаются в Hi пользовании других значений в поле типа (см табл. 1 в главе 1) и в том, что два байта, зарезервированные в вентилях прерывания и исключения процессора i80286, используются процессором i80386 для хранения битов 16-31 32-разряд- яого смещения Мультизадачность В процессоре i80386 получила дальнейшее развитие аппаратная поддержка мультизадачное™, впервые введённая в процессоре i8028t>. На рис. 22 представлен формат сегмента TSS для процессора i80386. Из рису- нка видно, что в TSS предусмотрены поля для хранения сегментных регистров GS, FS, DS, SS, CS, ES (процессор i80386 имеет два новых сегментных регистра - GS и FS). Имеется поле для хранения содержимого регистра LDTR, указываю- щего па локальную таблицу дескрипторов, распределённую данной задаче. Для хранения содержимого 32-разрядных регистров используются поля TSS, обозначенные на рисунке как EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX, EFIAGS, EIP Поле CR3 хранит содержимое системного регистра CR3. Этот регистр являет- ся у казателем на каталог таблиц страниц. Таким образом, каждая задача может иметь свой собственный каталог таблиц страниц, что позволяет выполнить изо- ляцию задач не только на уровне сегментов, но и на уровне страниц. ‘Дналог-мифи’
118 Защищённый режим процессоров Intel 80286/80386/80486 База карты ввода-вывода 0 It 0 LDTR 0 GS 0 PS 0 DS а SS 0 cs 0 E5 EDI ESI EBP ESP E8X EDX ECX ro EFLAGS ep СЯЗ 0 SS2 ESP2 0 SSI ESP1 0 sso ESPO 0 Рис. 22. Сегмент TSS процессора i80386 TSS процессора i80386 содержит указатели на стеки для второго, первого нулевого приоритетных колец. Это поля SS2:ESP2, SSLESPl, SSO:ESPO. Поле LINK используется для ссылки на TSS, вызвавшей задачи при вложен ном вызове задач, аналогично тому, как это было в процессоре i80286. Бит Т используется для отладки. Если он установлен в 1, при переключени на задачу возникает отладочное исключение, которое может быть использовач системным отладчиком. Есть ещё одно очень интересное новшество, введённое в процессор i80386, битовая карла ввода/вывода Что это такое? Для обеспечения безопасной работы системы необходимо ограничить дося программам пользователя ко всем или по крайней мере к некоторым порт | ввода/вывода. Злонамеренная программа, имеющая доступ к портам кон1ь и ра прямого доступа к памяти, может выполнить с помощью этого контроллер чтение или запись информации по любым физическим адресам. Процес I i80286 хранит в регистре флагов уровень привилегий IOPL, на котором разре! но выполнять команды ввода/вывода. С помощью этого механизма можно з П ретить непривилегированным программам выполнять команды ввода/вывода. Одкако такой способ защиты не слишком удобен. Некоторые порты ввода/вы вода не только безопасны для использования, но и весьма полезны для обычны' программ (например, порт системного динамика или принтера) Битовая карта ввода/вывода процессора i80386 позволяет для каждой задач । определить порты, которые эта задача может использовать. То есть операцион
Особенности процессоров /80366 и /80486 119 вая система имеет возможность санкционировать любую задачу для использова- ния любого набора адресов портов ввода/вывода. Если задача попытайся обра- титься к несанкционированному порту ввода/вывода, произойдёт исключение. Сегмент TSS содержит ноле, обозначенное на рис. 22 как база карты вво- да/вывода. Оно служит для указания расположения битовой карты ввода/вывода задачи, используюшей данный TSS Поле базы карты ввода/вывода указывает 16-разрядчое смещение начата би- товой карты ввода/вывода относительно TSS. Предел TSS должен определяться с учётом карты. Каждый бит в карте ввода/вывода соответствует адресу байта порта ввода/вывода. После битовой карты должен располагаться байт OFFh. При выполнении 16- или 32-разрядных операций ввода/вывода процессор проверяет все биты (2 или 4 бита), соответствующие адресу порта Если прове- ряемый бит установлен в 1, происходит исключение. Для привилегированных программ, если уровень привилегий меньше или ра- вен уровню IOPL, процессор не выполняет проверку битовой карты ьвода/ьыво да. Чтобы полностью запретить задаче обращаться к портам ввода/вывода, дос- таточно установить базу карты ввода/вывода большей или равной пределу TSS. В этом случае любая команда ввода/вывода приведёт к генерации исключения. Режим виртуального процессора 18086 Процессор i80386 содержит средства для работы в так называемом режиме ви- ртуального процессора 18086, называемого также для краткости режимом V86 или просто виртуальным режимом. Заметим, что до разработки фирмой Intel процессора 180836 термин ’’виртуальный режим" иногда использовался в литера- туре для обозначения защищённого режима работы процессора 180286. R режим V86 процессор может перейти из защищённое режима, если устано- вить в регистре флагов EfLAGS бит виртуального режима (VM-бит) Номер бита VM в регистре EFLAGS - 17 Когда процессор i80386 находится в виртуальном режиме, его поведение во многом напоминает поведение хорошо знакомого нам процессора i8086 В част- ности, для адресации памяти используется схема <сегмент:смещение>, размер се- гмента составляет 64 Кбайта, а размер адресуемой памяти - I Мбайт Виртуальный режим предназначен для работы программ, ориентированных на процессор 18086 (или 18088). Но виртуальный режим это не реальный режим процессора 18086, имеются существенные отличия Процессор фактически продо- лжает использовать схему преобразования адресов памяти и средства мультиза- дачное™ защищённого режима. В виртуальном режиме используется трансляция страниц памяти. Это позво- ляет в мультизадачной операционной системе создавать несколько задач, |>абота- ющих в виртуальном режиме Каждая из этих задач может иметь собственное ад- ресное пространство, каждое размером з 1 Мбайт Все задачи виртуального режима обычно выполняются в третьем, наименее Привилегированном кольце защиты. Когда в такой задаче возникает прерывание, ’ДИАЛОГ-МИФИ’
120 Защищённый режим процессоров Intel 80286/80386/80486 процессор автоматически переключается из виртуального режима в ч щищённый. Поэтому все прерывания отображаются в операционную систем^ работающую в защищённом режиме. Обработчики прерываний защищённого режима могут моделировать функци прерываний реального режима, что необходимо для правильной работы про, рамм, ориентированных на реальный режим операционной системы MS-DOS. j Виртуальные машины Обычно мультизадачные операционные системы предоставляют для выполи^ ния 18086-программ ’’виртуальные машины i8O86”. Эти виртуальные машины р< ализуются при помощи задач виртуального режима. Операционная система может виртуализовать ресурсы компьютера - памяти порты ввода/вывода, систему обработки прерываний. При этом программа, орие тированная на реальный режим MS-DOS, получает в своё распоряжение pecyj сы, которые она воспринимает как физические. Виртуализация памяти заключается в преобразовании адреса форма! реального режима <сегмент:смещение> в линейный, а затем и физический использованием схемы преобразования адресов защищённого режима. В это случае программе предоставляется 1 Мбайт памяти, который может быть раси| ложен в любом месте физической памяти компьютера и может подвергаться св< пингу на диск для реализации виртуальной оперативной памяти. С точки зренв программы, работающей на виртуальной машине, адреса отображаются на этс 1 Мбайт памяти так, как будто это была физическая память компьютера. Виртуализация ввода!вывода основана на том, что такие команды, как If OUT, INS, OUTS, CLI, STI, чувствительны к текущему уровню IOPL. Так хл обычно виртуальная машина работает в непривилегированном третьем коль) защиты, выдача этих команд программой в виртуальном режиме приводит к иа лючению. Операционная система может эмулировать действие этих команд бе! опасным для себя образом, что, однако, может привести к существенному заме) лению работы виртуальной машины. Виртуализация прерываний основана на выходе процессора из виртуально! режима и возврате в защищённый при возникновении прерываний. При возни! новении прерывания управление получает обработчик защищённого режима, у< тановленный операционной системой. Операционная система может эмулирова' функции соответствующего обработчика реального режима, например функця обработчика прерывания INT 21 h MS-DOS или BIOS. Переключение в защищённый и реальный режимы Процессоры i80386 и 180486 могут легко переключаться из реального режи» в защищённый и обратно с помощью команды MOV. Младший бит РЕ системн, го регистра CRO (см. приложения 3, 4) определяет текущий режим работы пр< цессора. Если этот бит установлен в 1, процессор работает в защищённом реж, ме, а если в 0, - в реальном.
Особенное г и процессоров i80386 и /80486 121 Для переключения процессора из реального режима в защищённый можно ис- пользовать, например, такую последовательность команд: mov ах, сг0 or ах, 1 mov сг0, ах Для совместимости с процессором i80286 оставлена возможность переключе- ния в защищённый режим с помощью команды LMSW. Для возврата в реальный режим необходимо сбросить бит РЕ: mov ах, сг0 and ах, 0fff'e mov сг0, ах х Таким образом, существует более красивый способ возврата в реальный ре- жим, чем выполнение аппаратного сброса или перевод процессора в состояние отключения (конечно, вы по-прежнему можете пользоваться старым способом перевода процессора в реальный режим). Перед переключением в реальный режим из защищённого программа должна выполнить следующие действия: обеспечить равенство линейных адресов физическим; отключить трансляцию страниц, сбросив бит PG в регистре CRO; загрузить ноль в регистр CR3 для сброса кэш-памяти страниц; передать управление сегменту кода с пределом 64 Кбайта; загрузить в сегментные регистры SS, DS, ES, FS, GS селекторы дескрипто- ров, подготовленных для адресации памяти в реальном режиме и содержа- щих соответствующие реальному режиму значения; запретить маскируемые и немаскируемые прерывания; сбросить бит РЕ, переключив процессор в реальный режим; выполнить команду дальнего перехода для очистки внутренней очереди команд процессора; настроить систему прерываний для работы в реальном режиме; разрешить прерывания; загрузить в сегментные регистры значения, необходимые для работы в реальном режиме. Как видите, процедура возврата в реальный режим сильно упростилась и ус- корилась по сравнению с использованной для процессора i80286. Однако боль- шинство программ, переключившись в защищённый режим, никогда больше не возвращаются назад. Они либо всё время работают в защищённом режиме, либо переключаются в режим виртуального процессора 8086. Процессор S80486 В этом разделе мы очень кратко опишем последнее на момент написания дан- ной книги достижение фирмы Intel - процессор (80486 Этот 32-разрядный быст- 'ДИАЛОГ-МИФИ
122 Защищенный режим процессоров Intel 80286/80386/80486 родействующий процессор специально предназначен для работы мультизадач^Д операционных систем, таких, как UNIX или OS/2. Процессор 180486 полностью совместим с более ранними моделями - ,8ов| i80286, i80386, но в то же время обладает существенно более высоким быстр . действием. Наиболее часто встречающиеся в программах команды выполняю^, за один машинный цикл. На кристалле процессора находится 8-килобайтпы» кэш оперативной памяти, обеспечивающий высокую производительность дь*, при использовании относительно медленной памяти. Кроме того, процессор 180486 содержит встроенный 32-разряднь:й арифмети- ческий сопроцессор, значительно увеличивающий скорость выполнения арифм: тических команд С точки зрения прикладного программиста процессор 180486 практически <ч отличается от процессора i80386 (за исключением более высокой произвол тельности). Все отличия касаются только системного уровня. Так как програк мирование процессора 180486 -на системном уровне - достаточно сложный пи цесс, мы нс станем описывать этот процессор во всех подробностях. Как прав*, ло, большинство программистов никогда не работают с системными регистр»» процессоров i80386 и 180486. оставляя эту работу операционной системе ил> драйверам расширенной памяти 8 процессоре 180486 определены некоторые, зарезервированные ранее в про- цессоре i80386, биты регистров CRO, CR3, EFLAGS. есть некоторые новшества табпииах страниц, новое исключение и несколько новых команд. В регистре CR0 определены пять новых битов - NE, WP, AM, NW, CD. В регистре CR3 определены два новых бита PCD и PWT. В регистре EFJ.AGS появился новый флаг АС (бит 18). Этот бит вместе с 1-1 том AM регистра CR0 контролирует проверку выравнивания объектов в памяти Форматы системных регистров CR0 и CR3 для процессора i8048t>, а также И гистра EFLAGS описаны в приложениях 1 4 и 5. Новое исключение касается проверки выравнивания и имеет номер 17. О-и возникает при попытке обращения к данным, ле выравненным в памяти Для w- го, чтобы при обращении к невыравненному операнду в памяти произошло и 1 лючение контроля выравнивания, должны быть установлены флаг АС в региепг EFLAGS и бит AM в управляющем регистре CR0 Заметим, что исключение контроля выравнивания генерируется только в П|У" граммах, работающих в третьем, непривилегированном кольце. Добавились три команды, предназначенные для использования прикладные программами - BSWAP, XADD, CMPXCHG, а также три новые системные kowi нды, управляющие кэшем и TLB, - INVD, WB1NVD, INVLPG. Новые команд облегчают и ускоряют работу с семафорами, что очень важно для мультизгы’1 ных операционных систем Есть также некоторые изменения в формате команды MOV, используемой . 1 доступа к тестовым регистрам. Появились новые регистры для работы с кэшем-
Особенности процессоров i80386 и 180436 123 В целом можно отметить, что архитектура процессора 180486 не претерпела революционных изменений по сравнению с процессором i80386. Поэтому в большинстве случаев прикладной программист может считать, что процессор 580486 - это очень быстрый вариант процессора i80386. 80286, 80386, 80486...Что дальше? В 1993 году должен появиться новый процессор - i80586. Предполагается, что он по своей производительности сможет составить реальную конкуренцию RISC- процессорам, используемым в рабочих станциях типа SUN. Фирма Intel пока хранит в секрете подробности архитектуры нового процессора, поэтому мы мо- жем только догадываться о его возможностях. Учитывая преемственность во всех процессорах, разрабатываемых фирмой Intel начиная с модели i8O8O, ^ожно предполагать, что этот суперсовременный скоростной процессор будет способен выполнять программы, разработанные ког- да-то для процессора 18086, причём с необычайно высокой скоростью! 'ДИАЛОГ-МИФИ’
Глава 6 ИЕРАРХИЯ СРЕДСТВ ДЛЯ РАБОТЫ В ЗАЩИЩЁННОМ РЕЖИМЕ Вы уже, наверное, обратили внимание на то, что программирование для защ щённого режима значительно сложнее, чем для реального, и требует учёта бол шого количества важных деталей. Даже для того, чтобы просто переве» процессор i80286 в защищённый режим, требуется провести основатель^ подготовительную работу. Процессоры i80386 и i80486 значительно сложи чем i80286. Использование всех возможностей этих процессоров доступно та ко высококвалифицированным системным программистам и требует подроби ознакомления с руководствами по процессорам, поставляемыми фирмой Intel. К счастью, существует программное обеспечение, облегчающее npoi создания программ для защищённого режима. Это программное обеспече выступает в качестве интерфейса между программой пользователя и некото управляющей программой (например, мультизадачной операционной систе защищённого режима). Мы рассмотрим средства, доступные программистам в среде MS-DOS ве; 5.0 и MS WINDOWS версий 3.0 и 3.1. Существует несколько уровней программной поддержки защищённого реж и поддержки работы с расширенной памятью: интерфейс BIOS; интерфейс драйвера HIMEM.SYS; интерфейс EMS/VCPI; интерфейс DPMI; расширители DOS (DOS-экстендеры). Интерфейсом самого низкого уровня является интерфейс. BIOS, npeflocraej мый программам в виде нескольких функций прерывания BIOS INT 15h. Ин' фейс BIOS позволяет программе перевести процессор из реального режима в щищённый, переслать блок памяти из стандартной памяти в расширенную наоборот. Этим все его возможности и ограничиваются. Интерфейс BIOS исп< зуется для старта мультизадачных операционных систем защищённого реж (таких, как OS/2) или в старых программах, работающих с расширенной па тью в защищённом режиме (например, СУБД ORACLE версии 5.1). Назначение драйвера HIMEM.SYS и его возможности были подробно опис во второй части второго тома "Библиотеки системного программиста” (глава 1 С помощью функций, предоставляемых этим драйвером, программа может вы лнять различные действия с блоками расширенной памяти, а также управлять, ресиой линией А20. Основное различие между способом работы с расширее памятью драйвера HIMEM.SYS и интерфейсом прерывания BIOS INT 15h ключается в том, что первый выполняет выделение программе и внутре!
Иерархия средств для работы в защищённом режиме 125 учёт блоков расширенной памяти, а второй рассматривает всю расширенную па- мять как один непрерывный участок. Если в системе установлен драйвер HIMEM.SYS, ваша программа не должна пользоваться прерыванием INT I5h во избежание конфликта со схемой распре- деления расширенной памяти, используемой драйвером. Однако драйвер HIMEM.SYS не открывает для программ доступ к защищённому режиму. Он по- лностью работает в реальном режиме, а для обращения к расширенной памяти использует либо недокументированную машинную команду LOADALL (если ис- пользуется процессор 80286), либо возможности процессора 80386, который по- зволяет адресовать расширенную память в реальном режиме (при соответствую- щей инициализации системных регистров и таблиц). В приложении 7 описаны действия, выполняемые командой LOADALL. Кома- нда полностью оправдывает своё название! (Load All - загрузить всё). Следующий уровень - интерфейс EMS/VCPI. Во втором томе "Библиотеки системного программиста”, в главе И, мы подробно рассматривали интерфейс EMS, который используется для работы с дополнительной памятью. Там же разъясняются отличия между расширенной и дополнительной памятью. Исполь- зуя трансляцию страниц, некоторые драйверы памяти (например, EMM386 или QEMM) могут эмулировать присутствие дополнительной памяти, используя рас- ширенную память. При этом стандартный набор функций управления дополни- тельной памятью, реализованный в рамках прерывания INT 67h, дополнен ещё несколькими функциями для работы в защищённом режиме процессора. Эти новые функции реализуют интерфейс виртуальной управляющей прог- раммы VCPl (Virtual Control Programm Interface). Они позволяют устанавливать защищённый и виртуальный режимы работы процессора, работать с расширен- ной памятью на уровне страниц и устанавливать специальные отладочные регис- тры процессора i80386. Интерфейс VCPI облегчает использование механизма трансляции страниц, освобождая программиста от необходимости работать с сис- темными регистрами процессора. Интерфейс DPMI (DOS Protected Mode Interface - интерфейс защищённого режима для DOS) реализуется модулем, называющимся сервером DPMI. Этот интерфейс доступен для тех программ, которые работают на виртуальной маши- не WINDOWS или OS/2 версии 2.0 (позже мы обсудим некоторые детали, свя- занные с использованием интерфейса DPMI в WINDOWS). Интерфейс DPMI предоставляет полный набор функций для создания одноза- дачных программ, работающих в защищённом режиме. В этом интерфейсе име- ются функции для переключения из реального режима в защищённый и обратно (!), для работы с локальной таблицей дескрипторов LDT, для работы с расши- ренной и стандартной памятью на уровне страниц, для работы с прерываниями (в том числе для вызова прерываний реального режима из защищённого режи- ма) , для работы с отладочными регистрами процессора i80386. Это наиболее раз- витый интерфейс из всех рассмотренных ранее. Последний, самый высокий уровень программной поддержки защищённого ре- жима - расширители DOS или DOS-экстендеры (DOS-extender). Они поставля- 'ДИАЛОГ-МИФИ'
126 Защищённый режим процессоров Intel 80286/80386/80486 ются, как правило, вместе со средствами разработки программ (трансляторами) Л виде библиотек и компонуются вместе с создаваемой программой в единый здВ грузочный модуль. DOS-экстендеры значительно облегчают использование защищённого режицЛ и расширенной памяти в программах, предназначенных для запуска из средЛ MS-DOS. Программы, составленные с использованием DOS-экстендеров, внешм очень похожи на обычные программы MS-DOS, однако они получают управдД ние, когда процессор уже находится в защищённом режиме. К формируемому с помощью DOS-экстендера загрузочному модулю добавь ются процедуры, необходимые для инициализации защищённого режима. Эц процедуры первыми получают управление и выполняют начальную инициалиа цию таблиц GDT, LDT, IDT, содержат обработчики прерываний и исключена систему управления виртуальной памятью и т. д. Пример DOS-экстендера, поставляемого вместе с транслятором - 38 DOS/Extender фирмы Phar Lap. Интерфейс BIOS Этот интерфейс реализуется в рамках прерывания BIOS INT 15h в компьют pax моделей IBM АТ на основе процессоров i80286, i80386 или i80486. Определить размер расширенной памяти Регистры на входе: АН 88h. Регистры на выходе: АХ Размер доступной расширенной памяти в килобайтах. Эта функция предназначена для определения размера расширенной памяП доступной для использования функциями прерывания INT 15h. Учтите, что, если в системе установлен драйвер HIMEM.SYS, функция 8 может вернуть нулевой размер доступной расширенной памяти. Некоторые про раммы (например, СУБД Oracle версии 51) могут оказаться несовместимыми! драйвером ЖМЕМ.SYS, т. к. они работают с расширенной памятью средства! прерывания INT 15h. Аналогичные проблемы могут возникнуть и при испольЭ вании других драйверов расширенной памяти, например QEMM. Как правило, драйверы расширенной памяти позволяют зарезервировать час расширенной памяти для программ, использующих интерфейс INT 15h. Для Я го необходимо задать соответствующие параметры. Например, для драйве HIMEM.SYS размер зарезервированной расширенной памяти можно указать сЛ дующим образом: device-c:\dos\himem sys /intl5=xxxx В этой строке "хххх" - размер зарезервированной памяти в килобайтах.
Иерархия средств для работы в защищённом режиме 127 Переслать блок расширенной памяти регистры на входе: АН 87h СХ Размер пересылаемого блока в словах ES:SI Адрес таблицы GDT, подготовленной специальным образом. - А*' регистры на выходе: CARRY 0, если функция выполнилась без ошибки АХ 00h. В случае ошибки: CARRY 1, если произошла ошибка при пересылке блока АН Код ошибки: 01 h - ошибка чётности; 02h - произошло исключение; \ 03h - сбой адресной линии А20. Перед вызовом этой функции необходимо подготовить GDT, состоящую из 6 дескрипторов. Два первых и два последних дескриптора должны содержать нули. Третий дескриптор должен указывать на начало области памяти, из которой бу- дет выполняться копирование. Четвёртый дескриптор должен указывать на об- ласть памяти, в которую будет выполняться копирование блока данных. В третьем и четвёртом дескрипторе необходимо заполнить поля предела для копируемого блока памяти (в них должно быть записано значение СХ*2 - 1) и поле доступа (значение 93) (табл. 6). Таблица 6. GDT для пересылки блока памяти средствами BIOS Смещение байта Содержимое 00h - OFh Это поле должно содержать нули 10h - llh Предел сегмента (СХ*2 -1) 12h - 14h 24-разрядный физический адрес исходного блока памяти 15h Байт доступа, должен быть равен 93h 16h - 17h Это поле должно содержать нули I8h - 19h Предел сегмента (СХ*2 -1) lAh - ICh 24-разрядный физический адрес результирующего блока памяти IDh Байт доступа, должен быть равен 93h lEh - 2Fh Это поле должно содержать нули Для пересылки блока функция 87h переводит процессор в защищённый ре- *им, используя подготовленную таблицу GDT. Так как указываются 24-разряд- вые физические адреса исходного и результирующего блоков, возможна пересы- 'Диадог-мифи
128 Защищённый режим процессоров Intel 80286/80386/80486 лка блоков из любого места памяти в любое место памяти. Размер блока, очеви- дно, ограничен 64 Кбайтами. Пересылка блока выполняется в защищённом режиме обычной командой MOVS, причём во время пересылки прерывания запрещены. Перед возврата^ функция выполняет сброс процессора и установку реального режима. Вся процедура пересылки оказывается длительной, т. к. необходимо выпод, нить сброс процессора. Из-за того, что во время пересылки прерывания запре. щены, возможен конфликт с устройствами ввода/вывода (потеря прерываний), ] Установить защищённый режим работы процессора Функция переключает процессор из реального режима в защищённый. Крона этого, она производит перепрограммирование контроллеров прерываний, неоЛ ходимое из-за конфликта используемых в реальном режиме векторов аппарап ных прерываний с зарезервированными прерываниями защищённого режима. Регистры на входе: » 1 АН 89h ВН Номер прерывания для IRQO, используется для перепрограммирования первого контроллера прерывания. Этот номер должен быть кратен 8 BL Номер прерывания для IRQ8, используется для перепрограммирования второго контроллера прерывания, j Этот номер также должен быть кратен 8 ES:S1 Адрес таблицы GDT, подготовленной специальным образом. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки АН 00h CS, DS, ES, SS В эти регистры заносятся значения в соответствии с подготовленной перед вызовом функции^таблицей GDT. 1 адрес которой задаётся в регистрах ES:SI. В случае ошибки: CARRY 1, при ошибке при входе в защищённый режим АН FF. Подготовленная перед вызовом функции 89h таблица GDT должна состоять восьми дескрипторов (табл. 7). ТоДлица 7. GDT для перехода в защищённый режим средствами BIOS Дескриптор Функциональное назначение О Пустой дескриптор, содержит нули во всех полях 1 > Дескриптор, описывающий таблицу GDT 2 Дескриптор, описывающий таблицу IDT
Иерархия средств для работы в защищённом режиме 129 3 Дескриптор для сегмента данных, соответствует селектору, который будет загружен в регистр DS 4 Дескриптор дополнительного сегмента данных (регистр ES) 5 Дескриптор сегмента стека (регистр SS) 6 Дескриптор сегмента кода (регистр CS) 7 Этот дескриптор инициализировать не надо, он будет использоваться функцией 89h для адресации сегмента данных BIOS В рамках прерывания INT 15h нет функции для возврата из защищённого ре- жима в реальный. Почему? Потому, что, во-первых, в защищённом режиме прерывание 15h зарезервиро- вано фирмой Intel, во-вторых, для работы в защищённом режиме вами подготав- ливается таблица IDT и определяются заново все обработчики прерываний. Об- работчики прерываний BIOS рассчитаны на работу в реальном режиме и после перехода в защищённый режим становятся недоступны. Пример использования интерфейса BIOS Наш пример демонстрирует использование функции 89h прерывания INT 15h для установки защищённого режима работы процессора. Программа устанавлива- ет защищённый режим, выдаёт первое сообщение и через некоторое время, вы- дав второе сообщение, возвращается в реальный режим. После того, как будет нажата любая клавиша, работа программы будет завершена. Обратите внимание на то, как в файле tos.c подготавливается таблица GDT. Адрес подготовленной таблицы передаётся функции protected_mode(), которая передаёт его функции 89h прерывания INT 15h. Вызов этой функции выполняе- тся в файле tossyst.asm. Листинг 16. Определение констант и структур данных. Файл tos . h tfdefine word unsigned int // Селекторы, определенные в GDT #define GDT_SELECTOR 0X08 // 1 - селектор для GDT #define #define IDT SELECTOR DATA_SELECTOR 0x10 // 2 - селектор для IDT 0x18 // 3 - селектор для DS #define VID_MEM_SELECTOR 0x20 // 4 - селектор для ES, // будет использован для адресации видеопамяти #define SS_SELECTOR 0x28 // 5 - селектор для SS ^define CODE-SELECTOR 0x30 // 6 - селектор для CS #define BIOS_SELECTOR #define COLOR_VID_MEM ^define MONO_VID_MEM 'ДИАЛОГ-МИФИ" 0x38 // 7 - селектор для // адресации области данных BIOS 0xb8000L 0xb0000L
130 Защищённый режим процессоров Intel 80286/80386/80486 ♦define M0N0_M0DE 0x07 ♦define BW_80_MODE 0x02 ♦define COLOR_80_MODE 0x03 typedef struct descriptor ( word limit; word base_lo; unsigned char base_hi, unsigned char type_dpl, unsigned reserved; } descriptor; typedef struct gate { word offset; word selector, unsigned char count; unsigned char type_dpl, word reserved, } gate; ♦define DESCRIPTOR-SIZE ♦define GATE SIZE (sizeof(descriptor)) (sizeof(gate)) (sizeof(idt)) ♦define IDT_SIZE ♦define TYPE_CODE_DESCR 0X18 ♦define TYPE DATA DESCR 0x10 ♦define TYPE INTERRUPT_GATE 0x86 ♦define TYPE_TRAP_GATE 0x87 ♦define SEG WRITABLE 0x02 ♦define seg^readable 0x02 ♦define SEG_EXPAND_DOWN 0X04 ♦define SEG_ACCESSED 0X01 ♦define SEG_PRESENT_BIT 0x80 ♦define EOI 0x20 ♦def ine MASTER8259A 0x20 ♦define SLAVE8259A 0xA0 ♦define MK_LIN_ADDR(seg,off) (((unsigned long)(seg))<<4) + (word)(of f) Листинг 17. Главная программа. Файл tos.с ♦include <stdio.h> ♦include <stdlib.h> ♦include <dos.h> ♦include <conio.h> ♦include ”tos.h" void Init_And_Protected_Mode_Entry(void); void protected_mode(descriptor far ’gdtptr); void real_mode(void); void init_gdt_descriptor(descriptor "descr, unsigned long base word limit, unsigned char type); void vi_print(unsigned int x,unsigned int y.char ‘s.char attrl void vi_hello_msg(void);
Иерархия средств для па боты и защищённом режиме 131 vcid exception_0(void), void exception-! (.void) . oid exception—2(void); void exception_3(void); vi ,d exception._4(void); lid exception_5(void), void exception_6(void), d exception_7(void), d exception—8(void), old exception—9(void); nd exception_A1 void); id exception B(void); id exception_C(void), d exception_D(void), id exception_E(void); id exception_F(void); void exception_10(void), .‘i d exception—11(void) jid exception_12(void), id exception_13(void), d exception_!4(void), -id except юп_15( void) id exception_16(void) old exception_17(void), >id exception 18(void), d exception__19(void) ; v d exeeption_lA(void), id exception_lB(void), id except:on_lC(void), id exception_lD(void), d exception_lE(void), iid exception-!Fivoid), //{ prg_abort(0); ) //{ prg_ abor t (1); } //{ prg_abort(2); J //{ prg__abort(3) ; } //{ prg_abcrt(4); ) //{ prg_abort(5); j //[ prg_abort(6); ) //{ prg_abosrt(7) , 1 //{ prg_abort(8); ) //{ prg_abort(9); } //{ prg_abort(0xA); ) //[ prg_abort(0xB); j //[ prg_ abort (0x0 , ) //{ prg_abort(0xD), I //( prg_abort(0xE), j //{ prg._abort(0xF) , ) //{ prg_abort(0xl0); 1 //( prg_abort(0xll), ) //{ prg_abort(0x!2), , //( prg._abort(0xl3); } //( pig_abort(0x14). } //{ prg_abort(0xl5); 1 //( prg_abort(0xl6); 1 //[ prg_abort(0xl7); ) //{ prg_abort(0xl8), I //{ prg_ibort(0xl9), ) //{ prg_abort(0xlA) 1 //{ prg_abort(0xlB', 1 //[ prg_abort(0xlC), ) //{ prg_abort(MxlD), ) //{ prg_abort(0xlE); I //[ prg_abort(0xlF); ) ' v -id iret0(void), id iretl(void), ( icriptor gdt[8]; gate idt[ ] = { [ (viord )&exceptiun_0, C0I3E_SELECT0R, 0, TYPE_7RAP_GATE, 0 }, //0 { (word)&except.ion 1, CODE_SELECTOR, 0. TYPE_TRAP_GATE, 0 }, // 1 { (?rord)iexcept on JI, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, //2 { (word)£exception_3, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), // 3 I (W0'-d)£exception 4, CODE SELECTOR, 0, TYPE_TRAP_GATE, 0 ], //4 [ (word)&exception_5, CODE-SELECTOR, 0. TvPE_TRAP-GatE, 0 }, //5 ( (word)i£excaptian_6, CODE-SELECTOR, 0, TYPE-TRAP_GATE,01, //6 { (word )<<i-except ion I, CODE—SELECTOR , 0. TYPE_TRAP_GATE, 0 }, // 7 { (word)&exception-3, CODE-SELECTOR, 0. 5
132 Защищённый ражим процессоров Intel 80286/80386/80486 ( ( { ( { { ( { ( ( ( ( { ( { ( { ( { { { { [ [ [ { ( TYPE_TRAP_GATE, 0 }, //8 (word)<&exception_9, CODE_SELECTOR. 0, TYPE_TRAP_GATE, 0 } , //9 (word )<&exception_A, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ], //A (word)£exception_B, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // В (word)&exception_C, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), // C (word )<fiexcept ion_D, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // D (word)&exception_E, CODE-SELECTOR, 0, TYPE—TRAP_GATE, 0 ), // E (word)&exception_F, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 } , // F (word)&exception_10, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ], //10 (word)<6exception_ll, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 1, //11 (word)<&exception_12, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //12 (word)<fiexception_13, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //13 (word)&exception_14, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), // 14 . (word)<6exception_15, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ], //15 (word)<£exception_16, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //16 (word)&exception_17, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //17 (word)<&exception_18, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ], //18 (wordMexceptiori—19 , CODE_SELECTOR , 0, TYPE_TRAP_GATE, 0 ], //19 (word)£exception_lA, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), // 1A (word)&exception_lB, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //IB (word)&exception_lC, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), // 1C (word)&exception_ID, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //ID (word )<£except ion_ IE , CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //IE (word)&exception_IF, CODE-SELECTOR, 0, TYPE_TRAP_GATE, 0 ), //IF (wordMiret0, CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ], //20 (word)&iret0, CODE—SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 1, //21 (word)&iret0, CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 1. //22 (word )<S1 ret0 . CODE—SELECTOR, 0,
Иерархия средств для работы в защищённом режиме 133 TYPE_INTERRUPT—GATE, 0 ), //23 { (word)<4iret0, CODE-SELECTOR, 0, TYPE—INTERRUPT_GATE, 0 ), //24 ( (word )<6iret0, CODE-SELECTOR , 0, TYPE_INTERRUPT_GATE, 0 ), //25 { (word)&iret0, CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ], //26 { (word)<fiiret0. CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), //27 ( (word)<Siretl, CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), //28 { (word)&iret 1, CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), //29 ( (word)<fiiret 1 , CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), // 2A ( (word)&iretl, CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), // 2B { (wor.d)<fiiretl, CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ), // 2C ( (wordl&iretl , CODE-SELECTOR, 0, TYPE_INTERRUPT_GATfi, 0 ), // £D ( (word)fiiretl, CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 ) , // 2E { (word)fiiretl, CODE-SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 } // 2F word y=0; void main(void) I textcolor(BLACK); textbackground(LIGHTGRAY); clrscrO; Init_And-Protected_Mode_Entry(); enable_interrupt(); vi_hello_msg(); У=3; vi_print(0, y++, ” Вошли в защищенный режим”, 0x7f); pause(); vi_print(0, y++, ” Для возврата в реальный ’’ ’’режим нажмите любую клавишу’’, 0x7f); real_mode(); getch(); textcolor(WHITE), textbackground(BLACK); clrscrO; void init_gdt_descriptor(descriptor ’descr, unsigned long base, word limit, unsigned char type) [ desci—>base_lp = (word)base; descr->base_hi = (unsigned char)(base >> 16); desci—>type_dpl = type; descr->1imit = limit; desci—>reserved = 0; 'ДИАЛОГ-МИФИ'
134 Защищённый режим процессирое Intel 80286/80386/80486 void Init_And_Protected_Mode_Entry(void) { union REGS r; word crt_mode, extern word gvl_; // Дескриптор, описывающий таблицу GDT init._gdt_ descriptor(<figdt[ 1 ] , MK_LIN_ADDR(_DS, &gdt). sizeof(gdt)-l, TYPE_DATa_DESCR I SEG_PRESENT_BIT | SEG.WRITABLE); // Дескриптор, описывающий таблицу IDT init_gdt_descriptor(&gdt[2], MK_LIN_ADDR(_DS, £iat), (unsigned long11DT_SIZE-1, TYPE.DATA DESCR | SEG_PRESF.NT B1T | SEG^WRITaBLE) ; // Дескриптор сегмента данных init_gdt_descriptor(&gdt[3], MK_LIN_ADDR(_DS, 0). OxffffL TYPE_DATA_DESCR f SEG_FRESENT_BIT I SEG_WRITABLE), // Определяем текущий видеорежим r ,h.ah=15, int86(0xl0,<Sr ,&г) , crt_mode - r.h.al, // Инициализация дескриптора для видеопамяти // монохромного видеоадаптера if(crt_mode = M0NQJ40DE) ini t_gdt_descriptor (<e.gdt[ 4 ] , M()NO_VID MEM, 3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT T SEG_WRITABLE) // Инициализация дескриптора для видеопамяти // цветного видеоадаптера else if (ert_rnode—BW B0..MODE | | crt_mode==COLOR_80_MODE) jnit gdt descriptorC<Sgdt[4], COLOR_V1D_MEM, 3999, TYPE_DATA_DESCR | SEG_PRESENT_BJT | SEG_WRITABLE) I else { ргзntf(”\пИзвините, этот видеорежим недопустим.”); exit(-i), 1 J // Дескриптор для сегмента стека init_gdi_descriptor(£gdt[5k UK_LIN_ADDR(_DS, 0), 0xffffL, TYPE_DATA_DESCR J SEG_PPESENTJ3IT | SEG_WRITABLE), // Дескриптор для сегмента кода ini и gdt_descr i ptor (<Sgdt [ 6 ] , MK LIW ADDR( CS, 0) , 0xfff*fL, TYPE_CODE_DESCR I SEG_PRE3EN7_BIT I SEG_READABLE); // Входим в защищенный режим. В качестве параметра передаем // адрес подготовленной таблицы GDT protected_mode(gdt); ) void prg_abort(int err), void except;on_0(void) { prg_abort(0), } void exception-1(void) { prg_abort(1). ) void exception.-2(void) ( prg_abort(2) , } void except!on_3(void) { prg_abort(3), 1 void exception_4(void) { prg_abort(4), } void exception s(void) ( prg_abort(5) , }
Иерархия средств для работы в защищённом режиме 135 void exception_6(void) { prg_abort(6); ) void exception_7(void) [ prg_abort(7); ) void exception_8(void) { prg_abort(8); ] void exception_9(void) { prg_abort(9); ) void exception_A(void) [ prg_abort(0xA); ) void exeeption_B(. void) [ prg. abort(0xB); } void exception_C(void) i prg abort!0xC); ) void exception_D.(void) { prg_abort(0xD); I void exception_E(vold) { prg abort(0xE), ) void exception_F(void) { prg_abort(0xF), ) void exception_10(void) < prg_abort(0xi0), ) void exceptional (void) { prg_abort(0xll) ; 1 void exception_12(void) ! prg_abort(0xl2); J void exception_13(void) ( prg_abor-t(0xl3), ) void exception_14(void) ( prg_abort(0xl4); ] void exception_15(void) ( prg_abort(0xl5); ) void exception_16<void) I prg abort(0xlb); ] void exception_17(void) ! prg_abort(0xi7); ) void exception_18(void) { prg abort!0x18); ) void exception_19(void) { prg_abort(0xl9): ) void exception_lA(void) ( prg abort(0xlA). ) void exception_lB(void) i prg.abort(0xlB), 1 void exception_lC(void) ( prg_abort(0xlC); 1 void exception_10(void) I prg_aburt(0xiD); ) void exception_lE(void) ( prg_abort(0xlE); } void exception IF(void) ( prg, abort(0x1 F)) void prg_abort(int err) ( vi_print(l,y++,”---> Произошло исключение”, 0xc); real_mode(); gotoxy(1,24); cprintf("Исключение %X, нажмите любую клавишу”, err); getcW); textcolor(WHIТЕ); textbackground(BlACK); clrscrC); exi t(0), void iret0(void) ( asm ( push ax mov al,EOJ out MASTER8259A,a] pop ax pop bp < ret ) } void iretl(void) { asm ( push ax mov al,EOI out MASTER8259A,al out SLAVE8259A,al pop ax pop bp "ДИАЛОГ-МИФИ"
136 Защищённый режим процессоров Intel 80286/80386/80486 iret void vi_putch(unsigned int х.unsigned int у,char- c.char attr) i register unsigned int offset, char far *vid_ptr, offset-(y160) + (x’2); vi d_ptr-=MK_FP( V] D_MEM_SELECTOR, offset); •vid_ptr++=c; *vid_ptr=attr. void vi_print(unsigned int x,unsigned int y.char ‘s.char attr| j while(’s) vi_putch(x++, y, *s++, attr), void vi_hello_msg(void) ( vi_print'(0. 0. ” Protected moae monitor "TINY/OS", " "v.1.11 for CPU 80286 | (C) Frolov A ) , 19^2 ", 0x30'j Листинг 18. Функции для перехода в защищённый режим и возврата реальный режим ; Файл tossyst . asm IDEAL MODEL SMAoL RADIX 16 P286 DATASEG CMOS PORT EQU 70 PORT 6845 EQU 63h COLOR PORT EQU 03d4h MONO PORT EQU 03b4h STATUS PORT EQU 64h SHUT DOWN EQU Of eh INT MASK PORI EQU 21h VIRTUAL MODE EQU 0001 A20 PORT EQU 0dl A20 ON EQU 0df A20 OFF EQU 0ddh EOI EQU 20 MASTER8259A EQU 20 SLAVE8259A EQU 0a0h KBD PORT A EQU 60h KBD_PORT_B EQU 61h gdt off dw 7 gdt _seg dw 7 real ss dw 7 real sp dw 7 real es dw 7
Иерархия средств для работы в защищённом режиме 137 codeseg PUBLIC _real._mode, _protected..mode PUBLIC _enable_interrupt PUBLIC _pause pEOC _protected_moae NEAR push bp mov bp.sp mov ax.(bp+4I mov dx,!bp-»6] mov [gdt_segl dx mov [gdt_offl, ax push ds mov ax,40 mov ds,ax mov (WuRD 67],OFFSET shutdown_rerurn mov [WCRC 69 I cs pop ds cli in al, INT_MASK_PORT and al, 0ffh out INT.MASK_PORT, al mov al,8f out CMOS_PORT,al jmp delayl delayl mcv al 5 out CMOS PORT+1,al mov real_ssJ,ss mov [real_es],es Загружаем регистры ES SI адресом GDT, полученным как параметр функции protected_mode() mov es, [gdt_seg] mov si, igdt_off] , Подготавливаем номера прерываний 1RQ0 и IRQtJ , для перепрограммирования контроллеров прерываний. mov bx, 2028h , Устанавливаем защищенный режим работы mov ах, 8900h int 15h jnc рок Если произошла ошибка, мы остались в реальном режиме, завершаем работу программы mov ah 4ch int 21h Установлен защищенный режим работы процессора! Рок: pop bp ret ENDP _protected_mode 'ДИАЛОГ МИФИ'
138 Защищённый режим процессоров Intel 80286/80386/80486 PROC _real_mode NEAR mov [real_sp], sp mov al, SHUT_DOWN out STATUS_PORT, al waitri: hit jmp waitrl LABEL snutdown_return FAR mov ax, DGROUP mov ds, ax assume ds:DGROUP cli mov ss,[real_ss] mov sp,[real_sp] in al, INT_MASK_PORT and al, 0 out INT_MASK_PORT, al mov ax, DGROUP mov ds, ax mov ss. ax mov es, ax mov ax,00Wdh out CMOS_POKT,al sti ret ENDP _real_mode PROC _pause NEAR push ex mov ex,10 ploop0 push ex xor ex,ex ploopl loop ploopl pop ex loop ploop0 pop ex ret ENDP _pause PROC _enable_interrupt NEAR sti in al. INT_MASK_PORT and al, 0fch out INT_MASK_PORT, al ret ENDP _enable_interrupt end
Иерархия средств для работы в защищённом режиме 139 Интерфейс 'IIMEM.SYS Как уже отмечалось, назначение драйвера HIMEM.SYS и его возможное™ бы- ли подробно описаны во втором томе ’’Библиотеки системного программиста” (глава 10). Поэтому здесь мы не будем подробно рассматривать эти функции и говорить об их использовании, а приведём только краткий перечень (табл. 8). Таблица 8. Функции XMS функция Назначение ООН Получить версию XMS (XMS - extended Memory Specification - спецификация расширенной памяти) Olh 02h 03h 04h 05h (>6h 07h 08h OOh OAh OBh OCh Запросить управление областью старшей памяти НМЛ Освободить область НМ А Глобальное разрешение линии а20 Глобальное запрещение линии А20 Локальное разрешение линии А20 Локальное запрещение линии А20 Определение текущего состояния линии А20 Определение размера свободной расширенной памяти Получить блок расширенной памяти ЕМВ Освободить блок ЕМ В Копирование блоков расширенной памяти ЕМВ Блокирование блока ЕМВ Для заблокированного ЕМВ можно определить его физический адрес OOh OEh OFh lOh lih Разблокирование ЕМВ Получить информацию об индексе ЕМВ Изменить размер блока ЕМВ Запросить управление областью UMB Освободить область UMB Для проверки наличия в системе драйвера, по,одерживающего спецификацию XMS, необходимо загрузить в регистр АХ значение 4300b и вызвать прерывание INT 2Fh. Если в регистре AL окажется значение 80h, драйвер установлен. В этом случае можно получить адрес управляющей программы, которую надо вызывать для выполнения функций. Если загрузить в регистр АХ значение 4310л и вы- звать прерывание INT 2Fh, в регистрах ES:BX будет записан искомый адрес. Как можно заметить, функции XMS позволяют управлять линией А20 и копи- ровал. блоки расширенной памяти. Но вы не найдёте среди них функции для пе- рехода в защищённый режим! 'ДИАЛОГ-МИФИ'
14 Защищённый режим процессоров Intel 80286/80336/80486 И это не случайно. Всё дело в том, что для работы с расширенной памятью драйвер HIMEM.SYS, реализующий спецификацию XMS, не использует защи- щённый режим работы процесора! Как это может быть? Ведь процессор, находясь в реальном режиме, не может адресовать память за границей первого мегабайта. Секрет заключается в том, что для процессора i80286 драйвер HIMEM.SYS использует недокументированную машинную команду LOADALL. Эта команда предназначена для тестирования процессора и не приведена в документации на процессор i80286 (см. описание команды LOADALL в приложении 7). С помощью этой команды можно выполнить загрузку всех регистров процес- сора, в том числе и некоторых недоступных программам Используя нестандарт- ную загрузку регистров, драйвер HIMEM.SYS может адресовать расширенную память, находясь в реальном режиме Такой способ адресации расширенной памяти значительно ускоряет процед копирования по сравнению с использованием функции 87h прерывания INT 15г- Кроме того, во время копирования функцией OBh драйвера H1MEM.SYS преры- вания остаются разрешёнными. Процессор i80386 тоже имеет недокументированную команду LOaDALL. Она отличается от имеющейся в процессоре i80286 кодом и выполняемыми действия ми. Хотя процессор i80386 способен адресовать расширенную память находясь ъ реальном режиме (при соответствующей загрузке системных регистров, которая может быть выполнена с использованием только документированных команд). В том, что на уровне интерфейса HIMEM.SYS не используется защищённым режим, заключена ещё одна причина, по которой мы не стали подробно рассмат- I ривать этот интерфейс в книге, посвящённой защищённому режиму Использование интерфейса HIMEM.SYS справдано в тех случаях, когда для работы вашей программы требуется буфер памяти большого размера, которым может быть размещён только в расширенной памяти. Однако программа не смо жет непосредственно адресовать этот буфер и вынуждена выполнять операцию копирования данных из стандартной памяти в расширенную и обратно, что ведёт к непроизводительной потере времени В приложении 8 описана утилита MEMOSCOB. Эта утилита выводит на экран список установленных в системе драйверов дополнительной памяти и доступны) интерфейсов с защищённым режимом В файле xmmc.asm находятся функции для работы с интерфейсом XMS. Этот файл и сами функции XMS были подробно описаны во втором томе ’’Библиотеки системного программиста”. Интерфейс EMS/VCPI Вс второй части второго тома "Библиотеки системного программиста” (глав.- И) мы рассказывали вам о дополнительной памяти и об использовании для ри боты с ней спецификации EMS - Expanded Memory Specification Драйверы дополнительной памяти предоставляют программам интерфейс пре- Ч рывания INT 67h, который мы тогда подробно описали. Мы также говорили >
Иерархия средств для работы в защищенном режиме 141 том, что для компьютеров на базе процессоров i80386 или 180486 существуют прайверы памяти, эмулирующие дополнительную память с использованием рас- ширенной. Самые известные драйверы такого типа - EMM386.SYS и QEMM.SYS. Эти драйверы используют защищённый (точнее, виртуальный) режим работы процессора i80386 и страничную адресацию расширенной памяти. Для приклад- ных программ предоставляется интерфейс, который называется VCP1 - Virtual Programrr. Control Interface Этот интерфейс реализован как подфункции функции DEh прерывания INT 67h (табл. 9) Таблица 9. Функции интерфейса VCPI Подфункция Выполняемые действия 00 Проверить наличие в системе интерфейса VCPI 01 Получить адрес точки входа для работы с интерфейсом VCPI 02 Определить максимальный физический адрес памяти 03 Определить количество свободных страниц памяти размером 4 Кбайта 04 Получить страницу памяти 05 Освободить страницу памяти 06 Получить физический адрес страницы памяти, располагающейся в пределах первого мегабайта, т е в стандартной памяти 07 Прочитать содержимое системного регистра CR0 08 Прочитать содержимое отладочных регистров 09 Установить отладочные регистры 0А Получить отображение векторов прерываний, используемых контроллерами прерываний 8259 0В Установить отображение векторов прерываний, используемых контроллерами прерываний 8259 ОС Переключить процессор из реального в защищённый режим, а также из защищённого в виртуальный режим Перед вызовом прерывания INT 67h регистр АН должен содержать DEh, а но- мер требуемой подфункции должен быть загружен в регистр AL. Кроме того, прежде чем вызывать прерывание INT 67h, в самом начале работы программы необходимо убедиться в том, что в системе установлен драйвер EMS. О том, как это сделать, мы рассказывали ь главе 11 второго тома "Библиотеки системного прщраммиста”. Там же приведён соответствующий пример программы. Функции VCPI позволяют перевести процессор в защищённый или виртуаль- ный режим работы и предоставляют программам полноценный доступ к расши- ренной памяти. Поэтому использование интерфейса VCPI более предпочтитель- но, чем интерфейса драйвера HIMEM.SYS, особенно в тех случаях, когда требу- ется интенсивная работа с расширенной памятью. "ДИАЛОГ-МИФИ"
142 Защищённый режим процессоров Intel 80286/80386/80436 Другое принципиальное новшество интерфейса VCPI - поддержка схемы пре образования адресов процессоров 180386/180486, а именно страничной памяти С помощью VCPI программа может легко получать и освобождать страницы па мяги, не работая непосредственно с щ сгемпыми регистрами процессора. Драйверы EMM386 и QEMM обеспечивают для программ DOS интерф(й, VCPI и сами пользуются _>тим интерфейсом. Вы знаете, что в пределах первого мегабайта адресного пространства имеется 640 Кбайт пак яти. Остальная памят, используется видеоадаптерами. ПЗУ BIOS и другой аппаратурой. Вся эта па.мяи называется зарезервированной памятью. Зарезгрвирова. ная память задействов; на не полностью, в ней есть oki Страницы памяти, соответствующие свобод ным окнам, с использованием механизма трансляции страниц отображаются » адресное пространство за пределами первого мегабайта памяти, т е. на расгв| ревную память. При этом для npoipaMM DOS появляется возможность воспользоваться окнами зарезервированной памяти для размещения там драйверов и резидентных прог- рамм. Процессор при этом работает, разумеется, не в реальном режиме, а в вир туальном, т. к. в реальном режиме трансляция страниц не исгользуется, Рассмотрим функции интерфейса VCP1 более подробно. Проверка наличия и системе интерфейса VCP! г егистры на входг АХ ODEOOh. Регистры на выходе: АН равен 00b - если VCP1 установлен, не равен 00h - если VCPI не установлен ВН Верхний (major) номер версии VCPI BL Нижний (minor) номер версии VCPI Получить адрес интерфейса VCPI Регистры на входе: АХ ODEOlh ES'DI Адрес буфера размером в 4 Кбайта для таблицы страниц DS:SI Адрес GDT, состоящей из трёх элементов, в первый будет записан дескриптор сегмента кода, остальные два будут использованы драйвером VCP1. Регистры на выходе: АН равен 00h - успешное выполнение функции, не равен 006 - ошибка DI Номер первого свободного элемента в таблице страниц, которая размеиюнг. в заказанном ранее буфере ЕВХ Смещение в сегменте кода точки входа в защищённый режим
Иерархия средств для работы в защищенном режиме 143 Определить максимальный физический адрес памяти Регистры на входе: АХ OOEOlh. Регистры на выходе; АН равен 00й - успешное выполнение функции, не равен 00h - ошибка EDX Максимальный физический адрес страницы памяти в 4 Кбайта. Определить количество свободных страниц памяти Регистры на входе: АХ ODEO3h Регистры на выходе1 АН равен ООП - успешное выполнение функции, не равен 00b - ошибка EDX Количество свободных страниц памяти, доступных для всех задач в системе. Эта функция доступна в защищённом режиме через вызов драйвера в его ин- терфейсной точке, адрес которой можно получить с помощью функции 01 h. Получить страницу памяти Регистры на входе; АХ 0DE046 Регистры на выходе: АН равен 00h - успешное выполнение функции, не равен 00h - ошибка EDX Физический адрес полученной страницы памяти Программа, использующая эту функцию, перед завершением своей работы должна освободить все полученные страницы памяти. Эта функция доступна в защищённом режиме через вызов драйвера в его ин- терфейсной точке Освободить страницу памяти Регистры на входе АХ 0DE05h EDX Физический адрес освобождаемой страницы памяти. Регистры на выходе: АН равен 0011 - успешное выполнение функции, не равен 00h - ошибка. Эта функция доступна в защищённом режиме через вызов драйвера в его интерфейсной точке. "ДИАЛОГ МИФИ'
144 Защищённый режим процессоров Intel 80286/80386/80486 Получить физический адрес страницы памяти, располагающейся в пределах первого мегабайта Регистры на входе: АХ 0DE06h СХ Номер страницы, равен линейному адресу страницы, сдвинутому вправо на 12 бит. Регистры на выходе: АН равен 00h - успешное выполнение функции, не равен 00h - неправильный номер страницы EDX Физический адрес страницы. Прочитать содержимое системного регистра CR0 Регистры на входе: АХ 0D^07h Регистры на выходе: АН 00h ЕВХ Значение системного регистра CR0. Прочитать содержимое отладочных регистров Регистры на входе: АХ 0DE08h ES:DI Адрес буфера размером 8 двойных слов. Регистры на выходе: АН 00h ЕВХ Значение системного регистра CR0. В буфере располагается содержимое отладочных регистров в следующем поря- дке: DRO, DR1, DR3, DR4, DR5, DR6, DR7. Регистры DR4 и DR5 зарезервиро- ваны и в процессоре i80386 не используются. Установить отладочные регистры Регистры на входе: АХ 0DE096 ES:DI Адрес буфера размером 8 двойных слов, содержащего новые значения для отладочных регистров. Регистры на выходе. АН 00h ЕВХ Значение системного регистра CR0. Значения, подготовленные для зарезервированных регистров DR4 и DR5, игнорируются.
Иерархия средств для работы в защищённом режима 145 Получить отображение векторов прерывании для контроллеров прерываний 8259 регистры на входе: АХ ODEOAh регистры на выходе: ЛН равен OOh • успешное выполнение функции, не равен OOh - ошибка ВХ Вектор прерывания, используемый для IRQ0 СХ Вектор прерывания, используемый для IRQ8 Установить отображение векторов прерывании для контроллеров прерываний 8259 Регистры на входе- АХ ODEOBh ВХ Вектор прерывания, используемый для IRQ0 СХ Вектор прерывания, используемый для IRQ8. Регистры на выходе: АН равен OOh - успешное выполнение функции, не равен OOh - ошибка После выполнения этой функции прерывания запрещены. Перед завершением своей работы программа должна установить прежнее отображение векторов для контроллеров прерываний. Переключить процессор в защищённый режим Регистры на входе АХ ODEOCh ESI Линейный адрес массива значений для системных регистров, массив должен располагаться в первом мегабайте памяти Регистры на выходе: Загружаются регистры GDTR, IDTR, LDTR, TR. В стеке, на который указы- вают регистры SSESP, необходимо отвести по крайней мере 16 байт для возмо- жности обработки прерываний. Содержимое регистров EAX, ESI, DS, ES. FS, GS после выполнения функции будет потеряно. Перед вызовом функции прерывания должны быть запрещены. После выпол- нения переключения в защищённый режим прерывания также запрещены. Приведём формат области для загрузки системных регистров перед переходом В защищенный режим (табл. 10). 'ДнЛЛОГ-МИФИ
146 Защищённый режим процессоров Intel 80286/80386/80486 Таблица 10. Формат буфера для загрузки регистров и перехода в защищённый режим средствами VCP1 Смещение Размер и назначение OOh DWORD, значение для регистра CR3 04h DWORD, линейный адрес г пределах первого мегабайта для загрузки регистра GDTR 08h DWORD, линейный адрес в пределах первого мегабайта для загрузки регистра IDTR OCh WORD, значение для регистра LDTR OEh WORD, значение для регистра TR iUh PWORD, значение адреса CS.E1P точки входа в защищенный режим Переключить процессор в виртуальный режим Переключение можно выполнить, если, находясь в защищённом режиме, вать точку интерфейса VCP1 с регистрами, загруженными следующим образом АХ DEOCh. DS Селектор, полученный от функции DEOlh SS:ESP Стек должен быть расположен в пределах первого мегабайта памяп Пример программы Приведём пример программы, определяющей присутствие в системе драйва и* дополнительной памяти ХММ, Если этот драйвер присутствует, программа пр->- веряет поддержку этим драйвером интерфейса VCPI. Затем, если интерфеж VCPI поддерживается, программа выводит его версию на экран Листинг 19 Определение версии VCPI Файл vepi.с #include <stdio.h> #include <dos.h> void main(void) ( unsigned err; char ver, ver_hi, ver_lo; clrscr(), printf("Virtual Control Program Interface Demo, ” "(C) Frolov A V , 1992\n\r" "-------------------------------------------------------\n\r\n\r”). // Проверяем наличие драйвера EMS/VCP1 if(ems_init()) ( printf (. "Драйвер EMS/VCPI не загружен ”);
Иерархия средств для работы в защищённом режиме 147 exit(-l) ) printf("Драйвер EMS/VCPI загружен"); Выводим номер версии драйвера if((err = ems_ver(fiver)) != 0) { printf ("\пОшг.бка %02 2Х при определении ' "версии EMM", err); exit(-l), ) printf("ХпВерсия EMM’ %02.2Х”, ver); // Определяем присутствие VCPI и его версию if (vop.i_ver(fiver_hi, &ver_lo) != 0) { printf(”\пДрайвер EMM не поддерживает VCPI\n”); exit(-l), } printf("ЧпВерсия VCPI %02 2X %02 2X”, verjii. ver_lo). ) t" ' .Name ems_init : Title Функция проверяет установку драйвера EMS : Descr Эта функция проверяет наличие драйвера EMS : Proto int ems_init(void); : Params Не используются .Return Я - драйвер FMS установлен; * 1 - драйвер EMS не установлен. ’.Sample * * / ems_test с int ems_init(void) { void (—interrupt _far 'EMS_driver_adr)(void); char _lar ’EMS ariver_name, cnar test_nam?T8]; int i ; EMS_driver_adr = _dos ^etvect(0x67), FP_SEG(EMS_driver_name) = FP_SEG (EMS_driver_adr), FP_OFF( EMS_dri ver_name) =• 10, for(i"0, i<8; i++) test_name[i] = EMS_.driver_name{i] if(strncmp(test_name ’’EMYXXXX0" , 8) — 0) return(0); else return(1); 1 ’ Name • Title ems_ver Определение версии драйвера EMS ’ Descr Эта функция возвращает номер версии драйвера EMS в двоично-десятичном формате - Proto int ems_ver(char ’ver); Params char ‘ver - указатель на байт, в который будет записан цомер версии ДИАЛОГ МИФИ'
148 Защищённый режим процессоров Intel 80286/80386/80486 Return Номер версии драйвера EMS в формате BCD ‘.Sample ems_test.c int ems_ver(char ’ver) ( union REGS reg; reg. x. ax = 0x4600; int86(0x67, «reg, &reg); 'ver = reg.h.al; return(reg.h.ah); J int vcpi_ver(char 'ver_hi, char ‘ver_lo) { union REGS reg; reg.x.ax = 0xDE00; int86(0x67, <Sreg, fireg); *ver_hi = reg.h.bh; ‘ver_lo = reg.h.bl, return(reg.h.ah); } Интерфейс DPMI Для создания программ, работающих в защищённом 'режиме, фирмы Microsoft, Intel, IBM, Lotus, Phar Lap, Rational Systems, Borland, Quarterdeck раз* работали интерфейс с защищённым режимом - DPMI (DOS Protected Mode Interface). Пользуясь этим интерфейсом, программы, стартующие как обычные DOS-программы реального режима, могут переключиться в защищённый режим и работать с расширенной или даже виртуальной памятью. Интерфейс DPMI обеспечивается специальной программой, называемой сервером DPMI. Сервером может быть отдельная резидентная программа, либо средства для поддержи DPMI могут входить в состав операционной системы (например, WINDOWS и OS/2 версии 2.0 позволяют работающим под их управлением DOS-программим использовать интерфейс DPMI). В этом разделе мы кратко опишем функции DPMI. В разделе, посвященном виртуальной машине WINDOWS, приведём пример программы, работающей • защищённом режиме с использованием функций DPMI спецификации 0.9. Спе- цификация DPMI 0.9 поддерживается операционной системой WINDOWS версий 3.0 и 3.1, работающей в расширенном режиме на процессорах i80386 и 180486- Все функции DPMI реализованы в рамках прерывания INT 3lh, обработчиков этого прерывания является сервер DPMI. Прежде чем использовать функнив DPMI, программа с помощью описанных ниже функций прерываний INT 2Fh должна убедиться в присутствии поддержки DPMI, получить адрес процедур*1 переключения в защищённый режим и выполнить это переключение. Программа должна вызывать прерывание INT 31h после переключения в за- щищённый режим, в реальном режиме это прерывание вызывать нельзя.
Иерархия средств для работы в защищённом режиме 149 Получить адрес перехода а защищённый режим С помощью этой функции программа может определить наличие в системе интерфейса DPMI и получить адрес процедуры перехода в защищённый режим работы. Для вызова этой функции необходимо использовать прерывание INT 2Fh, за- грузив регистр АХ следующим образом: Регистры на входе: АХ 1687h. Если функция была успешно выполнена, в регистры будут записаны следую- щие значения: Регистры на выходе: АХ OOh ВХ Если установлен бит 0, данная реализация DPMI поддерживает работу с 32-разрядными программами CL Тип процессора: 02h - 80286; 03h » 80386; 04h - 80486 DH Верхний (major) номер версии используемой спецификации DPMI DL Нижний (minor) номер версии используемой спецификации DPMI SI Количество параграфов памяти, требуемых для личной области данных сервера DPMI. Программа должна заказать эту память у операционной системы перед переходом в защищённый режим ES:DI Адрес процедуры, которую необходимо вызвать для входа в защищённый режим. Если выполнение функции закончилось с ошибкой, содержимое регистра АХ не равно нулю. ' Вход в защищённый режим После того, как программа получила адрес процедуры для входа в защищён- ный режим, она может вызвать эту процедуру при помощи команды CALL. Пе- ред вызовом необходимо загрузить регистры: Регистры на входе: АХ Разрядность программы. Если программа является 32-разрядной, в регистре АХ необходимо установить бит 0 в единицу ES В этот регистр необходимо загрузить сегментный адрес буфера, который будет использован сервером DPMI. Размер буфера должен быть определён при помощи предыдущей функции (регистр SI). После загрузки регистров необходимо выполнить вызов процедуры с адресом, который был получен в регистрах ES:DI после вызова предыдущей функции. 'ДИАЛОГ-МИФИ
150 Защищённый режим процессоров Intel 80236/80386/80486 Если функция выполнилась успешно, флаг CARRY сброшен и программа вы- полняется в защищённом режиме. Регистры на выходе: CS Селектор, которому соответствует базовый адрес сегмента кода программы и предел 64 Кбайта SS Селектор для сегмента стека, базовый адрес соответствует стеку реального режима, предел - 64 Кбайта DS Селектор, соответствующий сегменту данных реального режима, предел - 64 Кбайта ES Селектор, указывающий на PSP программы с пределом 100h байт FS, GS 0 (если программа работает на процессоре i80386 или 180486) ESP Если программа работает в 32-разрядном режиме, старшее слово регистра ESP будет равно пулю. Остальные регистры не изменяются. Если функция выполнилась с ошибкой, флаг CARRY устанавливается в еди ницу и программа продолжает выполнение в реальном режиме. После входа в защищённый режим вам становится доступен интерфейс DPMI через функции прерывания INT 31h. Для завершения своей работы программа, использующая DPMI, должна вы- дать прерывание INT 21 h (функция 4Ch) - это обычный способ завершения про. грамм, работающих в среде MS-DOS. Приведём фрагмент программы, использующей DPMI. На примере этого фра- гмента мы покажем, как убедиться в том, что в системе имеется интерфейс DPMI, как войти в защищённый режим и завершить работу программы. ; Получаем адрес точки входа в защищенный режим mov ах, 1687h int 2Fh test ax, ax jnz Cant_Enter_PMode ; не можем войти в защищенный режим mov (PMode_Entry_Seg], es mov [PMode_Entry_Off], di ; Заказываем память для сервера DPMI (если это требуется) test si, si jz Enter_PMode_Now mov bx, si mov ah, 48h int 21h jc Cant_Enter_PMode mov es, ax ; Устанавливаем защищенный режим Enter_PMode_Now xor ax, ax call DWORD PTR [PMode_Entry_Off) jc Cant_Enter_PMode ; Программа работает в защиенном режиме.
Иерархия средств для работы в защищённом режиме 151 ;----->> Здесь располагаются строки вашей программы ; Завершение программы и возврат в DOS mov ах, 4C00h int 21h Определение текущего режима работы Если ваша программа может работать и в реальном режиме, и в защищённом, с помощью этой функции вы можете определить текущий режим работы. Для выполнения функции необходимо вызвать прерывание INT 2Fh, предва- рительно загрузив регистр АХ. Регистры на входе: АХ 1686h. Регистры на выходе: АХ 0, если программа работает в защищённом режиме под управлением DPMI; не равно 0, если программа работает в реальном или виртуальном режиме. Создать дескриптор а таблице LDT С помощью этой функции программа может создать один или несколько деск- рипторов в LDT, принадлежащей задаче, в рамках которой работает программа, т. е. для своей задачи. Вся работа по инициализации полученных дескрипторов должна выполняться самой программой, для чего в DPMI имеются соответствующие функции. Регистры на входе: АХ . OOOOh СХ Количество создаваемых дескрипторов. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка АХ Базовый селектор. Если программа заказывала несколько селекторов, АХ содержит первый селе- ктор из созданного массива. Для получения остальных селекторов необходимо воспользоваться функцией 00003h. Освободить дескриптор в таблице LDT Функция используется для освобождения дескрипторов, созданных в LDT предыдущей функцией. Регистры на входе: АХ OOOlh ВХ Селектор освобождаемого дескриптора. Регистры на выходе: 'ДИАЛОГ-МИФИ’
152 Защищённый режим процессоров Intel 80266/80386/80486 CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Для освобождения массива дескрипторов функцию необходимо вызывать дельно для каждого дескриптора. Преобразование сегмента в дескриптор Функция используется для преобразования сегментной компоненты адреса ального режима в дескриптор. Регистры на входе: АХ 0002h ВХ Сегментный адрес реального режима. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка АХ Селектор, соответствующий дескриптору, созданному для адресац сегмента реального режима. Дескриптор, созданный данной функцией, не может быть освобождён, по; му эту функцию имеет смысл использовать для адресации таких областей па ти, которые будут нужны на всём протяжении работы программы (область а ных BIOS, память видеоконтроллера и т. д.). Получить значение инкремента для вычисления следующего селектора в массиве Если вы создали несколько дескрипторов в LDT при помощи функции 00< то этой функцией будет возвращён только первый селектор, соответствующи первому дескриптору в созданном массиве. Для вычисления остальных селег ров ваша программа должна использовать функцию 0003h. Эта функция возв| щает значение, которое вы будете прибавлять к базовому селектору для выщ ления остальных селекторов в массиве. Регистры на входе: АХ ОООЗЬ. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка АХ Значение для инкремента базового селектора. Зарезервированные функции Функции 00046 и 0005h в спецификации DPMI версии 0.9 зарезервированы не должны вызываться из вашей программы.
Иерархия средств для работы в защищённом режиме 153 Получить базовый адрес сегмента С помощью этой функции ваша программа может определить 32-разрядный базовый адрес сегмента по его селектору. Регистры на входе: АХ ОООбЬ ВХ Селектор сегмента, для которого требуется получить базовый адрес. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка CX:DX 32-разрядный базовый адрес сегмента. Установить базовый адрес сегмента Эта функция устанавливает базовый адрес сегмента в дескрипторе, соответст- вующем заданному селектору. Вы можете модифицировать только те дескрипто- ры, которые создала ваша программа. Регистры на входе: АХ 0007h ВХ Селектор сегмента, для которого требуется установить базовый адрес CX:DX Устанавливаемый 32-разрядный линейный базовый адрес сегмента. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Установить предел сегмента Эта функция устанавливает предел сегмента в дескрипторе, соответствующем заданному селектору. Регистры на входе: АХ 0008h ВХ Селектор сегмента, для которого требуется установить новое значение предела CX:DX Устанавливаемое 32-разрядное значение предела сегмента. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Установить поле прав доступа в дескрипторе При помощи этой функции вы можете модифицировать поле прав доступа в дескрипторе, созданном вашей программой. Регистры на входе: АХ 0009h 'ДИАЛОГ-МИФИ'
154 Защищённый режим процессоров Intel 80286/80386/80486 ВХ Селектор сегмента, для которого требуется установить новые права доступа СЕ Байт прав доступа СН Расширение байта прав доступа для процессора 180386/180486, используется только 32-разрядными реализациями DPMI. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. В расширении байта прав доступа старший бит (бит 7) - бит гранулярности, который определяет интерпретацию поля предела (0 - предел в байтах, 1 - пре- дел в страницах). Бит 6 указывает режим работы процессора (0 - 16-разрядный, 1 - 32-разрядный). Бит 5 и 2 - 3 должны быть равны нулю. Бит 4 может содер- жать любое значение. Создание алиасного дескриптора для сегмента кода Так как в защищённом режиме модификация сегмента кода с использованием селектора CS невозможна, для решения такой задачи необходимо создать деск- риптор сегмента данных, который бы указывал на сегмент кода (т. е. имел бы та- кой же базовый адрес и предел). Такой дескриптор является алиасом дескрипто- ру сегмента кода и можёт быть создан при помощи функции OOOAh. Если алиас больше не нужен, он может быть уничтожен при помощи функции OOOlh. Регистры на входе: АХ OOOAh ВХ Селектор сегмента кода, для которого требуется создать алиас. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Получить дескриптор С помощью этой функции программа может скопировать в буфер размером 8 байт дескриптор, соответствующий заданному селектору. Регистры на входе: АХ OOOBh ВХ Селектор сегмента, для которого требуется получить дескриптор ES:(E)Dl Указатель на буфер размером 8 байт, в который будет скопирован дескриптор. Для 32-разрядных программ необходимо использовать регистр EDI. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка.
Иерархия средств для работы в защищённом режиме 155 Установить дескриптор Функция выполняет действия, обратные предыдущей, - копирует содержимое 8-байтового буфера в дескриптор, заданный селектором. Регистры на входе: АХ OOOCh ВХ Селектор сегмента, для которого требуется установить дескриптор ES:(E)DI Указатель на буфер размером 8 байт, из которого будет взята информация для установки !ескриптора. Для 32-разрядных программ необходимо использовать регистр EDI. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Программа может модифицировать только дескрипторы из своей локальной таблицы LDT, созданные там с помощью функции OOOOh. Получить конкретный дескриптор в таблице LDT Функция позволяет получить дескриптор по его селектору. Регистры на входе: АХ OOODh ВХ Селектор сегмента, для которого требуется получить дескриптор. (•истры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Для этой функции сервер DPMI резервирует первые 16 дескрипторов в табли- LDT. Программа может освободить полученные с помощью этой функции де- рипторы при помощи функции OOOlh. Получить блок памяти из пула свободной памяти DOS С помощью этой функции программа может получить от DOS блок памяти, лежащий в пределах первого мегабайта адресного пространства. Для полученно- го блока памяти функция создаёт один или несколько дескрипторов (в зависимо- <- и от размера блока) и возвращает как сегмент блока для реального режима, так и базовый селектор для доступа к блоку в защищённом режиме. Если размер запрошенного блока превышает 64 Кбайта, функция создаст мас- сив дескрипторов и возвратит базовый селектор. Для получения остальных селе- кторов вы сможете использовать зна‘...ние инкремента, полученное после вызова Функции ОООЗЬ. Дескрипторы, созданные этой функцией, можно освобождать только с помо- щью функции OlOlh. Регистры на входе: 'ДИАЛОГ-МИФИ’
156 Защищённый режим процессоров Intel 80286/80386/80486 АХ OlOOh ВХ Размер блока в параграфах (напомним, что размер параграфа составляет 16 байт). Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. В случае ошибки регистр АХ содержит код ошибки, полученный от DOS: 07h - разрушен блок МСВ; 08h - слишком большой размер заказанного блока. В последнем случае регистр ВХ содержит максимально возможный размер блока в параграфах АХ Сегмент реального режима полученного блока DX Селектор для доступа к полученному блоку в защищённом режиме, Освободить блок памяти, взятый из пула DOS Функция предназначена для освобождения памяти, полученной при помощи предыдущей функции. Регистры на входе: АХ OlOlh DX Селектор освобождаемого блока. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. В случае ошибки регистр АХ содержит код ошибки, полученный от DOS: 07h - разрушен блок МСВ; 09h - неправильное задание сегментного адреса освобождаемого блока памяти. Изменить размер блока памяти, полученного из пула DOS С помощью этой функции программа может увеличить или уменьшить размер блока памяти, полученного функцией OlOOh. Регистры на входе: АХ 0102h ВХ Новый размер блока памяти в параграфах DX Селектор модифицируемого блока. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. При ошибке регистр АХ содержит код ошибки, полученный от DOS 07h - разрушен блок МСВ;
Иерархия средств для работы в защищённом режиме 157 08h слишком большой размер заказанного блока. В этом случае регистр ВХ содержит максимально возможный размер блока в параграфах. 09h - неправильное задание сегментного адреса модифицируемого блока памяти. Полупить вектор прерывания реального режима Функция возвращает для заданного вектора прерывания адрес его обработчик ка в формате реального режима. Регистры на входе: АХ 0200И BL Номер прерывания. Регистры на выходе: CARRY О CX.DX Адрес обработчика прерывания в формате <сегмент:смещение>. Установить вектор прерывания реального режима Функция позволяет задать для любого вектора прерывания адрес обработчика в формате реального режима. Регистры на входе: АХ 020 lh BL Номер прерывания CX:DX Адрес обработчика прерывания в формате <сегмент:смещение>. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Получить адрес обработчика исключения с заданным номером Функция возвращает адрес текущего обработчика исключения с заданным но- мером в формате защищённого режима. Регистры на входе: АХ 02026 BL Номер исключения (00h - 1 Fli). Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка CX:(E)DX Адрес обработчика исключения в формате <селектор:смещение>. Установить адрес обработчика исключения с заданным номером Функция может быть использована для установки собственного обработчика Исключений. 'ДИАЛОГ-МИФИ'
158 Защищённый режим процессоров Intel 80286/80386/80486 Регистры на входе: АХ 0203h BL Номер исключения (OOh - 1 Fh) CX:(E)DX Адрес обработчика исключения в формате <селектор:смещение>. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Получить вектор прерывания защищённого режима Функция возвращает адрес обработчика заданного прерывания в формате за- щищённого режима. Регистры на входе: АХ 0204h BL Номер прерывания. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка CX:(E)DX Адрес обработчика прерывания s формате <селектор:смещение>. Установить вектор прерывания защищенного режима С помощью этой функции программа может установить собственный обработч чик защищённого режима для любого прерывания. Регистры на входе: АХ 0205h BL Номер прерывания CX:(E)DX Адрес обработчика прерывания в формате <селектор:смещение>.. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Эмуляция прерывания реального режима Эта функция предназначена для эмуляции выполнения прерывания в реаль- ном режиме. С её помощью вы сможете, находясь в защищённом режиме, обра* щаться к функциям BIOS, DOS и к другим прерываниям реального режима. Регистры на входе: АХ ОЗООЬ BL Номер прерывания ВН Байт флагов- Если установлен в единицу бит 0, выполняется сброс контроллера и линии А20. Остальные биты зарезервированы и должны быть сброшены в нуль СХ Количество слов, которые должны быть скопированы из стека . защищённого режима в стек реального режима
Иерархия средств для работы в защищённом режиме 159 ES: (Е) D1 Адрес управляющей структуры для вызова прерывания. регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка £S:(E)D1 Адрес модифицированной (в результате выполнения обработчика прерывания) управляющей структуры в формате защищённого режима. Управляющая структура содержит значения для инициализации регистров пе- ред вызовом эмулируемого прерывания реального режима. Её формат указан в цбл- И. Таблица It. Формат управляющей структуры для эмуляции прерывания реального режима средствами DPMI Смещение Регистр Смещение Регистр OOh EDI 22h ES 04 h ESI 24 h DS 08h EBP 26h FS OCh Зарезервировано 28h OS lOh ЕВХ 2Ah IP 1 14h EDX 2Ch CS 18h ECX 2Eh SP iCh EAX 30h ss 20h FLAGS Ваша программа, находясь в защищённом режиме, может не только вызвать ^срывание реального режима, но и передать параметры через стек, указав в оразляющей структуре их количество. Наример: push Parametrl push Parametr2 push Parametr3 mov ex, 3 , Копируем три параметра mov ax, 0301h int 31h add sp. 6 ; ; Восстанавливаем стек Обработчик прерывания реального режима получит стек, подготовленный сле- гшим образом: ^rametrl ^ametr2 ^<?ametr3 ’Для возврата ' Для возврата Указатель стека реального режима SS.SP установлен на слово, содержащее IP возврата. ^ОГ-МИФИ'
160 Защищённый режим процессоров Intel 80286/80386/80486 Вызов процедуры реального режима, заканчивающейся командой RET FAR Эта процедура позволяет выполнить вызов процедуры, предназначенной дд, работы в реальном режиме и возвращающей управление при помощи команды RET FAR. Регистры на входе: АХ 0301h ВН Байт флагов. Если установлен в единицу бит 0, выполняется сброс контроллера и линии А20. Остальные биты зарезервированы и должны быть сброшены в нуль СХ Количество слов, которые должны быть скопированы из стека защищённого режима в стек реального режима ES: (Е) DI Адрес управляющей структуры для вызова процедуры реального режима. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка ES:(E)DI Адрес модифицированной (в результате выполнения процедуры реального режима) управляющей структуры в формате защищённого режима. Вызов процедуры реального режима, заканчивающейся командой IRET Процедура вызывает процедуру, предназначенную для работы в реальном ре- жиме и возвращающей управление при помощи команды 1RET. Регистры на входе: АХ 0302h ВН Байт флагов. Если установлен в единицу бит 0, выполняется сброс контроллера и линии А20. Остальные биты зарезервированы и должны быть сброшены в нуль СХ Количество слов, которые должны быть скопированы из стека защищённого режима в стек реального режима. ES:(E)DI Адрес управляющей структуры для вызова процедуры реального режима. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка ES:(E)D1 Адрес модифицированной (в результате выполнения процедуре реального режима) управляющей структуры в формате защищённого режима. Перехват передачи управления программе реального режима Эта функция может быть использована для перехвата передачи управле®* процедуре реального режима.
Иерархия средств для работы в защищённом режиме 161 Например, драйвер мыши выполняет вызов процедуры реального режима при перемещении мыши. Программа может сама задавать адрес реальной процедуры, которая будет получать управление при перемещении мыши или при нажатии на её кнопки. С помощью данной функции программы защищённого режима могут перехватить передачу правления этой процедуры и заменить её на другую про- цедуру, работающую в защищённом режиме. Регистры на входе: АХ ОЗОЗЬ DS: (Е) SI Адрес процедуры в формате защищённого режима, которая будет вызвана вместо перехваченной ES:(E)DI Адрес управляющей структуры для вызова процедуры реального режима (в формате защищённого режима). Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка ES:(E)DI Адрес модифицированной (в результате выполнения процедуры реального режима) управляющей структуры в формате защищённого режима CX:DX Адрес вызова перехватываемой программы в формате реального режима. Процедура защищённого режима, перехватывающая управление, вызывается с запрещёнными прерываниями и получает следующие параметры: DS:(E)SI Адрес стека реального режима в формате <селектор:смещение>. ES:(E)DI Адрес управляющей структуры в формате <селектор:смещение>. SS:(E)SP Стек защищённого режима. Остальные регистры остаются в неопределённом состоянии. Для выполнения возврата из процедуры перехвата необходимо выполнить ко- манду IRET, предварительно загрузив регистры следующим образом: ES:(E)DI Адрес управляющей структуры в формате <селектор:смещение>. Отмена перехвата передачи управления процедуре реального режима Эта функция отменяет действие предыдущей. Регистры на входе: АХ 0304h CX:DX Адрес вызова перехватываемой программы в формате реального режима, для которой отменяется перехват. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. 'ДИАЛОГ-МИФИ' 6--3S4
162 Защищённый режим процессоров Intel 80286/80386/80486 Получить адреса процедур сохранения/восстановления состояния С помощью этой функции программа может сохранять или восстанавливать состояние задачи (в том числе содержимое всех регистров процессора). Это бывает необходимо перед изменением реального режима работы на защищённый и обратно. Регистры на входе: АХ 0305h. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка АХ Размер буфера для сохранения состояния ВХ:СХ Адрес программы сохранения/восстановления для реального режима в формате <сегмент:смещение> ES:(E)DI Адрес программы сохранения/восстановления для защищённого режима в формате <селектор:смещение>. Процедура сохранения/восстановления состояния вызывается командой CALL FAR и получает следующие параметры: BS:(E)DI Указатель на буфер сохранения состояния AL 0 - для сохранения состояния, 1 - для восстановления состояния. Получить адрес процедуры переключения режима С помощью этой функции программа может получить адреса процедур длв переключения из реального режима в защищённый и из него в реальный. Регистры на входе: АХ 0306h. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка ВХ:СХ Адрес программы переключения из реального режима в защищённый в формате <сегмент:смещение> SI:(E)DI ' Адрес программы для переключения из защищённого режима в реальный в формате <селектор:смещение>. Перед переключением режима, которое выполняется командой JMP FAR, нео- бходимо подготовить регистры: АХ Новое содержимое регистра DS СХ Новое содержимое регистра ES DX Новое содержимое регистра SS (Е)ВХ Новое содержимое регистра (E)SP SI Новое содержимое регистра CS (E)DI Новое содержимое регистра (Е)1Р.
Иерархия средств для работы в защищённом режиме 163 В процессе переключения режима содержимое регистра (Е)ВР останется неиз- менным, поэтому этот регистр можно использовать как указатель. Для процессоров i80386 и 180486 после переключения режима в регистры FS и GS будет записано нулевое значение. Получить версию спецификации DPMI Функция позволяет получить текущую версию DPMI. Регистры на входе: АХ 0400h. Регистры на выходе: CARRY 0 АН Верхний (major) номер версии AL Нижний (minor) номер версии ВХ Байт флагов: бит 0 = 1-, если программа работает под управлением DPMI для процессора i80386; бит 1 « 1, если процессор вернулся в реальный режим для обработки прерывания; бит 2*1, если в системе поддерживается виртуальная память; бит 3 и все остальные зарезервированы для использования в будущем CL Тип процессора: 02 - i80286 03 - i80386 04 » 180486 DH Текущее значение номера прерывания для IRQ0 DL Текущее значение номера прерывания для IRQ8. Получить информацию о свободной памяти Регистры на входе: АХ 0500h ES:(E)D1 Адрес буфера размером 30h байт ь формате <селектор:смещение> (табл. 12). Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка ES:(E)DI Адрес буфера размером 30h байт в формате <селектор:смещение>, заполненного информацией о свободной памяти. 'ДИАЛОГ-МИФИ' 6
164 Защищённый режим процессоров Intel 80286/80386/80486 Таблица 12. Формат буфера для информации о свободной памяти, получаемой средствами DPMI Смещение Описание OOh Размер наибольшего доступного свободного блока в байтах 04h . Максимальное количество доступных незаблокированных страниц памяти 08h Максимальное количество доступных заблокированных страниц памяти ОСЬ Размер линейного адресного пространства в страницах 10h Общее количество незаблокированных страниц 14h Количество свободных страниц 18h Общее количество физических страниц ICh Размер свободного линейного адресного пространства в страницах 20h Размер страничного файла или раздела в страницах 24h-2Fh Зарезервировано Если текущая реализация DPMI не поддерживает виртуальную память, данная функция заполняет только первое поле структуры. Остальные поля устанавлива- ются в-1 (OFFFFFFFFh). Получить блок памяти Эта функция предназначена для получения программой участка линейной па- мяти. Для полученного блока памяти не выполняется автоматическое создание селектора, программа должна создать селектор самостоятельно. Регистры на входе: АХ 0501h ВХ:СХ Размер блока памяти в байтах. < Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка ВХ:СХ Линейный адрес полученного блока SI:DI Индекс полученного блока памяти, нужен для выполнения операции с блоком памяти (изменение его размера или освобождение). Освободить блок памяти Освобождает блок памяти, полученный при помощи предыдущей функции. Регистры на входе: АХ 0502h SI:DI Индекс освобождаемого блока памяти.
Иерархия средств для работы в защищённом режиме 165 Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Изменить размер блока памяти Изменяет размер блока памяти, полученного при помощи функции 0501 h. Регистры на входе: АХ 0503h ВХ:СХ Новый размер блока памяти в байтах SI:DI Индекс изменяемого блока памяти. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка ВХ:СХ Новый линейный адрес полученного блока SI'.Dl Новый индекс блока памяти. Зафиксировать линейную область памяти Эта функция фиксирует в памяти область, задаваемую линейным адресом. Для зафиксированной области памяти не выполняется свопинг страниц. Регистры на входе: АХ ОбООЬ ВХ:СХ Начальный линейный адрес фиксируемого участка памяти SI:D1 Размер фиксируемого блока памяти в байтах. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Расфиксирование блока памяти Эта функция должна быть использована для расфиксирования блока памяти, зафиксированного предыдущей функцией. Регистры на входе: АХ 0601 h * ВХ:СХ Начальный линейный адрес расфиксируемого участка памяти SI:DI Размер расфиксируемого блока памяти в байтах. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. Отмена фиксации страниц для области памяти виртуального режима Область памяти, используемая виртуальной машиной, обычно зафиксирована и не подвергается свопингу. С помощью этой функции вы можете разрешить свопинг для заданного участка памяти, принадлежащей виртуальной машине. 'ДИАЛОГ-МИФИ’
166 Защищённый режим процессоре в Intel 80286/80386/80486 Pei истры на входе- АХ 0602b ВХ:СХ Начальный линейный адрес расфиксируемого участка памяти SPDI Размер расфиксируемого блока памяти в байтах. Регистры на выходе: C ARRY о, если функция выполнилась без ошибки; 1, если произошла ошибка. Фиксация страниц для области памяти виртуального режима Функция предназначена для отмены действия предыдущей функции. Она фи« сирует участок памяти виртуальной машины, отменяя для него свопинг страниц Регистры на входе; АХ 0603И ВХ:СХ Начальный линейный адрес фиксируемого участка памяти SI:DI Размер фиксируемого блока памяти в байтах. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка Получить размер страницы памяти Функция возвоашает размер страницы памяти в байтах. Регистры на входе: АХ 06046 Регистры на выходе. CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка ВХ:СХ Размер страницы памяти в байтах. Зарезервированные функции Функции 07о0Ь и 0701 h зарезервированы и не должны вызываться ваП1Ы- программой. Отметка страницы для свопинга ' Функция используется, чтобы сообщить операционной системе о возможности выгрузки (свопинга) на диск указанной страницы или диапазона страниц. Регистры на входе: АХ O7o2h ВХ.СХ Начальный линейный адрес отмечаемых страниц S1DI Размер отмечаемого блока памяти. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка.
Иерархия средств для работы в защищённом режиме 167 Отвергнуть содержимое страниц Функция отмечает страницы как не содержащие полезной информации Опе- рационная система может использовать данные страницы для удовлетворения за- просов на память. Регистры на входе: АХ , 0703h ВХ:СХ Начальный линейный адрес страниц, отмечаемых как не содержащие полезной информации S1:DI Размер отмечаемого блока памяти в байтах Регистры на выходе: CARRY С, если функция выполнилась без ошибки; 1, если произошла ошибка. Преобразование физического адреса в линейный Функция может быть использование* для работы с периферийными устройства- ми, адресное пространство ввода/вывода которых отображается в диапазон фи зических адресов. Регистры на входе: АХ 0800h ВХ:СХ Физический адрес памяти SI DI Размер блока памяти в байтах. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка ВХ:СХ ' Линейный адрес памяти Запретить виртуальные прерывания Функция сбрасывает флаг виртуального прерывания и возвращает предыдущее состояние этого флага. Регистры на входе: АХ 09006. Регистры на выходе. CARRY 0 AL 0, если виртуальные прерывания были запрещены; 1, если виртуальные прерывания были разрешены. Разрешить виртуальные прерывания Функция устанавливает флаг виртхальных прерываний, разрешая виртуальные прерывания, и возвращает предыдущее состояние этого флага. Регистры на входе: АХ 0901 h. •ДИАЛОГ МИФИ’
168 Защищённый режим процессоров Intel 80286/ 80386/80486 Регистры на выходе CARRY О AL 0, если виртуальные прерывания были запрещены, I, если виртуальные прерывания были разрешены Получить состояние флага виртуальных, прерываний Функция позволяет узнать текущее состояние флага виртуальных прерывания Регистры на входе: АХ 0Q02h. Регистры на выходе: CARRY О AL 0, если виртуальные прерывания запрещены; I, если виртуальные прерывания разрешены. Получить адрес для использования расширений DPMI DOS-экстендеры могут расширять сервис DPMI своими функциями Для полу чения доступа к этим функциям можно использовать функцию ОАООп. Вызываю- щая программа должна задать в регистрах DS:(E)SI адрес строки, закрыто* нулём. Строка должна содержать название производителя DOS-экстендера или другой уникальный идентификатор расширения Регистры на входе’ АХ OAOOh DS:(E)SI Указатель на строку, закрытую нулём. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; I, если произошла ошибка ES:(E)DI Точка входа для вызова расширений. Содержимое регистров DS, FS, GS, EAX, ЕВХ, ЕСХ, EDX, ESI и ЕВР не сохраняется. Установить точку останова для отладки Функция позволяет установить отладочную точку останова по заданному ли нейному адресу Регистры на входе. АХ ОВООЬ ВХ:СХ / Линейный адрес точки останова DL Размер используемого для точки останова операнда (1,2 или 4 байта) DH, Тип точки останова: О - Выполнение, I = Запись, 2 = Чтение/запись.
Иерархия средств для работы в защищённом режиме 169 Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; I, если произошла ошибка ВХ Индекс для доступа к отладочной точке останова. Отмена отладочной точки останова Функция отменяет точку останова, установленную при помощи предыдущей функции. регистры на входе: АХ OBOIh ВХ Индекс отладочной точки останова. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; I, если произошла ошибка. г Получить состояние отладочной точки останова Функция возвращает состояние отладочной точки останова, определённой при помощи функции OBOOh. Регистры на входе: АХ 0B02h ВХ Индекс отладочной точки останова. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка АХ Флаги: бит 0=1, если произошло выполнение точки останова. Сброс точки останова Функция сбрасывает состояние для заданной отладочной точки останова. Регистры на входе: АХ ОВОЗЬ ВХ Индекс отладочной точки останова. Регистры на выходе: CARRY 0, если функция выполнилась без ошибки; 1, если произошла ошибка. DOS экстендеры Вы уже, наверное, заметили, что все программы, приведённые в этой книге, не поддаются отладке с помощью обычных отладчиков, таких, как Borland Turbo Debugger или Microsoft Code View. Эти отладчики ’’зависают” уже на этапе заг- РУзки регистра дескрипторной таблицы прерываний IDTR, до перехода в защи- 'диАлог-миа>и“
170 Защищённый режим процессоров Intel 80286/80386/80486 щённый режим дело так и не доходит. И это понятно - такие отладчики рассчи- таны на обычные программы реального режима. Другая трудность связана с тем, что программе, работающей в защищённом режиме, недоступны прерывания MS-DOS и BIOS. Программа должна работать < аппаратурой на уровне регистров и аппаратных прерываний. Для облегчения разработки программ, стартующих из MS-DOS в реальном pt жиме и переключающихся в защищённый режим, разработаны специальные сре- дства, называемые DOS-экстендерами или расширителями DOS. Эти средства прикомпоновывают к разрабатываемой программе специальны! модуль, реализующий интерфейс с защищённым режимом. Программа, создан- ная с использованием DOS-экстендера, загружается специальным загрузчиком в память и получает управление, когда процессор уже находится в защищённом режиме. Всю работу по переводу процессора в защищённый режим и по обрабо- тке прерываний в защищённом режиме берёт на себя экстендер. Кроме того, DOS-экстендер предоставляет программе возможность обращения к прерываниям MS-DOS и BIOS! В своих программах, работающих в защищён- ном режиме под управлением DOS-экстендера, можно пользоваться привычшймн функциями MS-DOS и BIOS (правда, не всеми, а только документированными). Возможности этих функций возрастут. Например, с помощью функции DOS мо- жно будет заказать для программы буфер размером в несколько мегабайт. Модуль DOS-экстендера, прикомпонованный к программе, может использо- вать интерфейсы DPMI, VCPI, XMS (драйвер HIMEM.SYS), INT I5h или может использовать собственную схему управления памятью в защищённом режиме собственные средства переключения режима процессора или состояния адресной линии А20. В спецификации DPMI приведены рекомендации для разработчиков DOS-экстендеров по использованию перечисленных выше интерфейсов. DOS-эк* стендер должен проверять наличие интерфейсов и по возможности использовать более высокоуровневый интерфейс. Проверка должна выполняться в следующей порядке: DPMI. EMS/VCPI. XMS. Функции прерывания INT 15h. К сожалению, не все поставляющиеся DOS-экстендеры соответствуют эти* рекомендациям. В результате могут возникнуть проблемы при попытке запустит* разработанную с помощью DOS-экстендера программу на виртуальной машяМ WINDOWS в режиме "Enhanced 386 Mode” или в MS-DOS при установлении! драйверах EMM386 или QEMM. Необходимость обеспечения совместимости с интерфейсами DPMI, VCPI 1 XMS требует тщательного выбора DOS-экстендера. Так как в настоящее врем! операционная система WINDOWS находится в состоянии взрывообразного раеп ространения среди пользователей персональных компьютеров, неудачный выбор DOS-экстендера может привести к тому, что огромное количество потенциала
Иерархия средств для работы в защищённом режиме 171 ных покупателей не смогут использовать вашу программу в среде WINDOWS. То же относится и к значительному количеству пользователей драйверов расши- ренной памяти EMM386 и QEMM. В документации на DOS-экстендер должно содержаться подтверждение совместимости с интерфейсами DPMI, VCPI и XMS. Такой DOS-экстендер будет совместим с современными операционными система- ми и драйверами расширенной памяти. Примерами программ, созданных с использованием несовместимых с DPMI интерфейсом, служат СУБД ORACLE версии 5.1 и FOXPRO версии 2.0. Эти программные продукты не будут работать на виртуальной машине WINDOWS в режиме "Enhanced 386 Mode”. Исходные тексты программ, составленных для DOS-экстендеров, внешне очень похожи на тексты программ реального режима. В них отсутствуют строки, специфические для программ, рассмотренных нами ранее и выполняющие пере- ключение в защищённый режим, либо подготовку системных таблиц, либо пере- программирование контроллера прерывания. DOS-экстендеры поставляются в комплекте с трансляторами, редакторами связей, отладчиками и библиотеками стандартных функций (например, библио- теками для транслятора языка Си). Поэтому создание и отладка программ защи- щённого режима, созданных с использованием DOS-экстендеров, обычно не вы- зывает затруднений. Мы кратко рассмотрим возможности двух DOS-экстендеров: 386- DOS/Extender фирмы Phar Lap и виртуальную машину операционной системы WINDOWS в режиме "Enhanced 386 Mode”. Phar Lap DOS-экстендер В состав Phar Lap DOS-экстендера входят транслятор для языка Си hc386.exe, ассемблер 386asm.exe, редактор связей 3861ink.exe, отладчик minibug.exe и прог- рамма загрузки run386.exe. С помощью транслятора языка Си или ассемблера получаются объектные модули, которые компонуются редактором связей 3861ink.exe в загрузочный модуль. Этот загрузочный модуль имеет расширение ”ехр” и запускается при помощи программы загрузки run386.exe. Полученный загрузочный модуль мо- жет работать только на процессорах i80386 или i80486. Версия 2.2 Phar Lap DOS-экстендера не поддерживает интерфейс DPMI, поэтому разработанные с ис- пользованием экстендера этой версии программы не будут работать на виртуаль- ной машине WINDOWS в режиме "Enhanced 386 Mode”. Phar Lap DOS-экстендер предоставляет программе, которая получает управле- ние сразу в защищённом режиме, возможность использовать документированные прерывания MS-DOS и BIOS. Кроме того, в рамках прерывания INT 21 h DOS- экстендером реализуются дополнительные функции, связанные с работой в за- щищённом режиме. 'ДИАЛОГ-МИФИ’
172 Защищённый режим процессоров Intel 80286/80386/80486 Для того, чтобы у вас было представление о возможностях Phar Lap DOS-экс. тендера, в табл. 13 приводятся дополнительные функции, реализованные - рамках прерывания INT 21h. Таблица 13. Функции Phar Lap DOS-зкстендсра Регистр АХ Выполняемая функция 2501h 2502h 2503h 2504h 2505h 2506h Установка в исходное состояние структур данных DOS-экстендера Получить вектор прерывания защищённого режима Получить вектор прерывания реального режима Установить вектор прерывания защищённого режима Установить вектор прерывания реального режима Установить режим, при котором прерывание будет всегда обрабатываться в защищённом режиме 2507h 2508h 2509h 250Ah 250Ch 250Dh 250Eh 250Fh Установить векторы прерываний реального и защищённого режима Установить линейный базовый адрес сегмента Преобразовать линейный адрес в физический Отобразить физическую память в конце сегмента Получить векторы аппаратных прерываний Получить информацию связи с реальным режимом Вызвать процедуру реального режима Преобразовать адрес защищённого режима в адрес реального режима 2510h Вызвать процедуру реального режима с заданным содержимым регистров 251 Ih Вызвать прерывание реального режима с заданным содержимым регистров • 2512h 2513h Загрузить программу для отладки Создать алиасный дескриптор сегмента (т. е. для заданного дескриптора создаётся ещё один, указывающий на тот же сегмент) 2514h 2515h 2516h 2517h 2518h 2519h 251Ah 251Bh 251Ch Изменить атрибуты сегмента Получить атрибуты сегмента Освободить всю память, распределённую при помощи LDT Получить информацию о буферах данных DOS Определить драйвер для обработки перемещения сегмента Получить дополнительную информацию об ошибке памяти Зафиксировать страницы в памяти Расфиксировать страницы Освободить страницы физической памяти
Иерархия средств для работы в защищённом режиме 173 251 Dh Прочитать элемент таблицы страниц 251 Eh Записать элемент таблицы страниц 251Fh Обменять элементы таблицы страниц 2520h . Получить статистическую информацию о памяти 2521h Максимальный размер доступной программам расширенной памяти 2522h Определить альтернативный драйвер, обрабатывающий ситуацию отсутствия страницы в памяти 2525h Максимальный размер доступной программам стандартной памяти 25C0h Получить блок стандартной памяти MS-DOS 25Clh Освободить блок стандартной памяти MS-DOS 25C2h Изменить размер блока стандартной памяти MS-DOS 25C3h Выполнить программу Сравните это с функциями интерфейса DPMI; вы увидите, что между этими интерфейсами есть много общего. Есть специальная функция, предназначенная для отладчиков, - ’’Загрузить программу для отладки”. Программе доступны селекторы, облегчающие работу с наиболее часто ис- пользуемыми областями данных. Например, таблица LDT содержит следующие селекторы, готовые для использования: Таблица 14. Таблица LDT Phar Lap DOS-экстсидера Селектор Назначение 0008h Сегмент кода программы OOlOh Сегмент данных программы 0018h Сегмент видеопамяти для работы в текстовом режиме 0020h PSP программы 0028h Сегмент строк среды DOS (DOS environment) 0030h Сегмент данных для доступа к первому мегабайту памяти, доступен для записи 0038Н Сегмент для работы с сопроцессором Weitek 1167. В отличие от сопроцессора 180287/180387 для обращения к сопроцессору Weitek 1167 используется определённая область адресов памяти 0040h Сегмент видеопамяти для работы в графическом режиме В документации на Phar Lap DOS-экстендер подробно описаны форматы таб- лиц LDT и GDT. Программы могут пользоваться определёнными в этих табли- цах селекторами для адресации системных областей памяти, таких, как память видеоадаптера. В качестве простейшего примера использования Phar Lap DOS- экстендера приведём следующую программу: 'ДИАЛОГ-МИФИ'
174 Защищённый режим процессоров Intel 80286/80386/80486 Листинг 20. Использование Phar Lap DOS-экстендера. Файл pharlap.asm Сегмент данных _data segment para public use32 ’data’ . hello db ’PHAR LAP 386/DOS EXTENDER’, 0dh,0ah db ’Вызов DOS в защищенном режиме', 0dh,0ah db 0dh,0ah,'(C) Frolov A.V., 1992’,0dh, 0ah db 0бЬ,0аЬ,'Для возврата в DOS нажмите любую клавишу’, data ends Сегмент стека _stack segment byte stack use32 ’stack’ db 8192 dup (?) stack ends ; Сегмент кода! assume cs:_text,ds:_data _text segment para public use32 ’code’ public _start_ _start_ proc near ; Выводим строку , lea edx,hello mov ah,09h int 21h ‘ . I mov ah,8h int 21h mov ax,04c00h int 21h _start_ endp _text ends end _start_ Эта программа просто выводит сообщение на экран и завершает свою работу после того, как вы нажмёте любую клавишу. Особенность программы заключае- тся в том, что она получает управление сразу в защищённом режиме. Запуск программы должен выполняться специальным загрузчиком, который входит в со- став Phar Lap DOS-экстендера. Этот загрузчик находится в файле run386.exe. Для трансляции программы и её запуска можно использовать следующий ко- мандный файл:
Иерархия средств для работы в защищенном режиме 175 386asrr. pharlap 3861ink pbarlap run386 pharlap Обратите внимание на то, что в приведённой выше программе не выполняется загрузка сегментного регистра DS. Так как программа стартует сразу а защищён- ном режиме, загрузчик гип386 загружает сам все сегментные регистры В частно- сти, он загружает в регистр DS селектор сегмента данных. Виртуальная машина WINDOWS Операционная система WINDOWS позволяет разделять ресурсы персонально- го компьютера между несколькими пара^шельно работающими программами. При этом в среде WINDOWS мшут выполниться три типа программ: Программы, созданные специально для работы под управлением WINDOWS, - приложения WINDOWS. Они не могут работать вне WINDOWS, т. к. для своей работы используют модули, находящиеся в яд- ре WINDOWS. Приложения WINDOWS всегда начинают своё выполнение и выполняются в защищённом режиме, им дщтупен интерфейс DPMI. Программы, созданные для работы в среде MS-DOS и ничего не знающие о WINDOWS Это хорошо знакомые вам программы реального режима. Если WINDOWS работает в стандартном режиме (Standart Mode) на ком- пьютере с процессором i80286, выполнение этих программ происходит в реальном режиме. Если WINDOWS работает в расширенном режиме (Enhanced Mode? на процессорах i80386 или i8048o, такие программы вы- полняются в режиме виртуального процессора 8086 Программы, начинающие свою работу в режиме виртуального процессора 8086 (как обычные программы реального режима) и переключающиеся затем в защищённый режим. Эти программы используют интерфейс DPMI, который доступен им только в том случае, если WINDOWS работа- ет в расширенном режиме на процессорах 180380 или 180486. Программы первого типа - тема для отдельной книги объёмом в несколько со- тен страниц (см список литературы). Программы второго типа это обычные программы MS-DOS, о которых мы говорили в предыдущих томах ’’Библиотеки системного программиста”. Мы займёмся программами последнего типа. Для составления этих программ вы можете использоьать обычную технику, применяемую для программ реально- го режима MS-DOS (за исключением отладки - как и все программы, при- ведённые в этой книге, программы третьего типа не поддаются отладке стандарт- ами для реального режима средствами). Наша следующая глава - о WINDOWS и о тех возможностях, которые опера- ционная система WINDOWS предоставляет программам, составленным в старом "пиле” MS-DOS ’ЛНАЛОГ-МИФИ“
Глава 7 ОПЕРАЦИОННАЯ СИСТЕМА Microsoft WINDOWS Не будет преувеличением сказать, что операционная система WINDOWS вер- сии 3.0 открыла новый этап в жизни персонального компьютера IBM PC. Удоб- ная, интуитивно ясная графическая оболочка, аналогичная используемой в ком- пьютерах фирмы Apple, быстро завоевала популярность у пользователей IBM PC. В нашей стране WINDOWS также получила широкое распространение, осо- бенно после того, как стали доступны компьютеры с памятью 2 Мбайта и более. Новая версия WINDOWS 3.1 обладает улучшенным графическим интерфейсом а большей производительностью. Однако WINDOWS - это не только графика и перекрывающиеся окна. С точ- ки зрения программиста WINDOWS является графически ориентированной мультизадачной операционной системой, работающей в защищённом режиме процессора. Стандартные приложения WINDOWS используют как бы- "вывернутую наиз- нанку” логику работы программ. Обычно, создавая программы для MS-DOS. программист полностью планирует сценарий работы программы. Он последова- тельно определяет, что и когда программа будет выводить на экран, что и когда должно быть введено с клавиатуры. Логика работы приложений WINDOWS основана на использовании очередей событий. Событием является, например, нажатие клавиши на клавиатуре, преры- вание от системного таймера, нажатие на кнопку мыши или перемещение мыши. Для каждого приложения создаётся своя собственная очередь, в которую запи- сываются коды событий и дополнительная информация о событиях (например, код нажатой клавиши). Приложение WINDOWS в цикле опрашивает состояние очереди событий. Если происходит какое-либо событие, вызывается соответствующий модуль, который и реагирует на событие. Перед обработкой событие удаляется из очереди. Программа не может знать последовательности событий, поэтому её поведете полностью определяется событиями, происходящими в системе. Такая логик* работы программ называется логикой, управляемой событиями, а сами програм- мы - программами, управляемыми событиями. Кроме изменений в логике работы программ, WINDOWS реализует новы* подход к использованию системных ресурсов. Операционная система MS-DOS ее содержит сколько-нибудь значительной поддержки диалоговых программ, поэто му программисты вынуждены прибегать к использованию специальных библио- тек, содержащих программы меню, управления окнами, модули для работы • мышью и графикой. Все необходимые модули прикомпоновывались к основной программе, сильно увеличивая размер загрузочного модуля.
Операционная система Microsoft WINDOWS Операционная система WINDOWS в своём ядре содержит все модули, необхо- димые для организации высококачественного графического диалога с пользова- телем. Причём нет необходимости в их компоновке с основным модулем - весь сервис WINDOWS реентерабельный, т. е. одни и те же модули используются все- ми одновременно работающими приложениями. Новый подход в создании программ, предложенный в WINDOWS, способству- ет созданию удобных программ с дружественным диалогом, использующих все доступные ресурсы компьютера. Однако WINDOWS едва ли получила бы такое широкое распространение, если бы она не позволяла одновременно с приложе- ниями WINDOWS использовать разработанные ранее программы, ориентирован- ные на MS-DOS (DOS-программы). В зависимости от типа процессора и режима, в котором работает WINDOWS (стандартный или расширенный) выполнение DOS-программ организуется по- разному. В стандартном режиме и при использовании процессора i80286 DOS-програм- мы выполняются в реальном режиме процессора. В любой момент времени мо- жет выполняться только одна DOS-программа, остальные запущенные DOS-про- граммы находятся в "замороженном” состоянии. Расширенный режим требует наличия процессора i80386 или i80486. Он орга- низует параллельную работу всех запущенных приложений WINDOWS и DOS- программ, выделяя в распоряжение каждому приложению и программе так назы- ваемую виртуальную машину. Виртуальную машину, на которой выполняется DOS-программа, мы будем называть виртуальной DOS-машиной. Что такое виртуальная машина, хорошо знают те, кто работал на ЕС ЭВМ в операционной системе VM (известна также под названием ”СВМ” - система вир- туальных машин). Все ресурсы компьютера разделяются между запущенными программами. В распоряжение каждой программы предоставляется собственный виртуальный процессор, виртуальная память, виртуальная система прерываний. Дисплей, клавиатура и мышь используются совместно и распределяются той программе, которая в данный момент работает с оператором (про такую прог- рамму разработчики приложений WINDOWS говорят, что она имеет ’’фокус вво- да” - input focus). Когда WINDOWS работает в расширенном режиме, процессор может нахо- диться либо в защищённом, либо в виртуальном режиме. DOS-программа полу- чает управление, когда процессор находится в виртуальном режиме. При этом, используя механизм трансляции страниц, WINDOWS отображает участок расши- ренной памяти в область младших адресов задачи, в рамках которой работает DOS-программа. Таким образом для DOS-программы организуется виртуальное адресное пространство, которое программа не может отличить от реальной памя- ти, расположенной в пределах первого мегабайта. Дополнительно в распоряжение DOS-программы может быть предоставлена расширенная или дополнительная память (интерфейсы EMS и XMS). Размер этой памяти можно задать в pif-файле (см. руководство по WINDOWS). "ДИАЛОГ-МИФИ’
178 Защищённый режим процессоров Intel 80286/8U386/80486 Если DOS-программа выдаёт команду программного прерывания, процессор переходит в защищённый режим и управление передается ядру WINDOWS WINDOWS эмулирует для DOS-программы все прерывания DOS и BIOS, анало- гично тому, как это делают DOS-экстендеры. Поэтому виртуальную DOS-маши- ну, на которой выполняется DOS-программа, можно считать DOS-экстендером. Для приложений WINDOWS и виртуальной DOS-машины доступен интерфейс DPMI. Эго означает, что виртуальная DOS-машина не просто допускает выпол- нение DOS-программ, но и предоставляет им дополнительные возможности, ко- торые они не имели бы, если бы работали под управлением MS-DOS Описанию дополнительных возможностей и посвящена данная глава книги. Использование функций DPMI Приведённая ниже программа демонстрирует использование функции интер- фейса DPMI, описанного в предыдущей главе. Эта программа может работать только под управлением WINDOWS версий 3.0, 3.1 и только в расширенном ре- жиме на процессорах 180386 или 180486. Такое ограничение связано с тем, что только в расширенном режиме существует понятие виртуальной DOS-машины и только в этом режиме DOS-программа может воспользоваться сервисом DPMI. Вы можете также попробовать запустить эту программу под управлением DOS-экстендера, входящего в состав интегрированной системы разработки прог- рамм Borland C++ 3 1 Запустите программу DPM1RES EXE, входящую в состав Borland C++ 3.1, и затем программу, приведенную ниже (DOS-экстендеры, вхо- дящие в состав Borland C++ 2 9 или 3.0. не вполне совместимы с DPMI, поэтому наш пример с этими системами работать не будет;. Программа начинает свою работу с проверки доступности сервера DPMI, при этом не делается никаких предположений относительно средств, обеспечиваю- щих присутствие DPMI. Это означает, что вы можете проверить работоспособ- ность этой программы в различных средах, предоставляющих интерфейс DPMI например на виртуальной DOS-машине операционной системы OS/2 версии 2.0 Программа демонстрирует возможность вызова « защищенном режиме преры- ваний реального режима В первой части программы вывод на экран и ввод с клавиатуры выполнятся в защищённом режиме, но с использованием привычных вам прерываний реального режима. Во второй части программы демонстрируется непосредственная запись в вн деопамять. Для адресации видеопамяти программа заказывает селектор в таблице LDT с помощью специально предназначенных для этого функций DPMI Листинг 21. Использование интерфейса DPMI ; Файл dpmi с «include 'stdio.li> «include <stdlib.h>
Операционная система Microsoft WINDOWS 179 /include <dos.h> /include <conio.h> /include <stdarg.h> typedef struct ( unsigned long edi, esi, ebp, reserved, ebx, edx, ecx, eax; unsigned flags, es, ds, fs, gs, ip, cs, sp, ss; } RM_INT_CALL; /define MONO_MODE 0X07 /define BW_80_MODE 0X02 /define COLOR_80_MODE 0x03 // Макро для вычисления линейного адреса, исходя из // логического адреса реального режима /define ABSADDR(seg, ofs) \ ((((unsigned long) seg) << 4) + ((ofs) & 0xFFFF)) typedef struct ( unsigned accessed : 1; unsigned read_write : 1; unsigned conf_exp : 1; unsigned code : 1; unsigned xsystem : 1; unsigned dpi : 2; unsigned present ; 1; ) ACCESS; // байт доступа typedef struct { // дескриптор unsigned limit; unsigned addr_lo; unsigned char addr_hi; ACCESS access; unsigned reserved; ) DESCRIPTOR; // Структура для записи информации о памяти typedef struct ( unsigned long avail_block; unsigned long max_page; unsigned long max_locked; unsigned long linadr_space; unsigned long total_unlocked; unsigned long free_pages; unsigned long tot_phys_pages; unsigned long free_linspace; unsigned long size_fp; char reserved!12]; ) PMI; void dos_exit(unsigned); void dpmi_init(void); void set_pmode(void), oid cdecl pm_printf(const char *, ...); void pm_puts(char •); void pm_putch(int); int rm_int(unsigned, unsigned , RM_INT_CALL far •); •ДИАЛОГ-МИФИ’
180 Защищённый режим процессоров Intel 80286/80386/80486 int mi_show(void); unsigned get_sel(void); int set_descriptor(unsigned pm_sel, DESCRIPTOR far ’desc); void vi_print(unsigned int x,unsigned int y,char 's.char attr); void vi_hello_msg(void); void main() ( clrscrO; printf("DOS Protected Mode Interface Demo, ” "(C) Frolov A.V., 1992\n\r" "------------------------------------------\n\r\n\r"); // Определяем текущий видеорежим // и сегментный адрес видеобуфера video_init() ; // Инициализируем защищенный режим dpmi_init(); printf("\п\г\п\г\п\гДля входа в защищенный ” "режим нажмите любую клавишу...’’); getchO; // Входим в защищенный режим set_pmode(); // Стираем экран и выводим сообщение, находясь // в защищенном режиме. Пользуемся выводом через // эмулируемое прерывание реального режима DOS textcolor(BLACK); textbackground(LIGHTGRAY); clrscrO; pm_printf(" Установлен защищенный режим работы" "процессора!\n\i--------------------------------\n\r\n\r" ) ; // Выводим текущую информацию о распределении памяти mi_show(); pm_printf("\n\r\n\r\n\r Для продолжения нажмите " "любую клавишу...”); getch(); clrscr(); // Получаем селектор для непосредственного // доступа к видеопамяти alloc_videosel(); pm_printf(”\n\r\n\r\n\r Для продолжения нажмите ” "любую клавишу...”); getchO ; clrscr(); // Выводим сообщения, пользуясь непосредственным доступом // к видеопамяти vi_hello_msg(); vi_print(0, 3, ” Для возврата в реальный режим ’’ "нажмите любую клавишу”, 0x7f); getch();
Операционная система Microsoft WINDOWS 181 // Освобождаем полученный селектор free_videosel(); textcolor(LIGHTGRAY); textbackground(BLACK), clrscrO; // Завершаем работу программы выходом в DOS dos_exit(0); ) // Процедура для завершения работы программы //--------------------------------------------------- void dos_exit(unsigned err) { asm mov ax, err asm mov ah, 04ch asm int 21h ) // Инициализация для работы c DPMI union REGS inregs, outregs, struct SREGS segregs, void (far •pm_entry)(); unsigned hostdata_seg, hostdata_size, dpmi_flags, void dpmi_init(void) ( // Проверяем доступность и параметры сервера DPMI inregs.х.ах = 0x1687; int86x(0x2F, <&inregs, Aoutregs, Asegregs); if(outregs,x.ax != 0) ( printf(’’Сервер DPMI не активен ’’); exit(-l); } // Определяем версию сервера DPMI printf("Версия сервера DPMI. \t\t\t%d %d\n”, outregs.h.dh, outregs.h.dl); // Определяем тип процессора printf("Тип процессора:\t\t\t\t"); if(outregs.h.cl =- 2) printf("80286”); else if(outregs.h.cl -= 3) printf(”80386"); else if(outregs.h.cl = 4) printf("80486”); // Определяем возможность работы с 32-разрядными программами dpmi_flags = outregs.х.bx; printf(”\пПоддержка 32-разрядных программ:\t”), if(dpmi_flags && 1) printf("ПРИСУТСТВУЕТ"); else printf("ОТСУТСТВУЕТ”); // Определяем размер области памяти для сервера DPMI hostdata_size = outregs.х.si; printf(”\пРазмер памяти для сервера DPMI:\t\t%d байт”, hostdata_size ' 16), // Определяем адрес точки входа в защищенный режим FP_SEG(pm_entry) = segregs.es; FP_OFF(pm_entry) = outregs x.di; "ДИАЛОГ-МИФИ*
182 Защищённый режим процессоров Intel 80286/80386/80486 printf (''-.пАдрес точки входа в защищенный режим \t%Fp\n" , pm_entry), // Заказываем память для сервера DPMI if(hostdata_size) { if(_dos allocmem(hostdata_size.<ihostdata_seg; != 0) { printf("Мало стандартной памяти’’); exit(-l), ) } ) //--------------------------------------------------- // Процедура для установки защищенного режима void set_pmode() { // Входим в защищенный режим asm { mov ах, hostdata_seg mov es, ax mcv ax, apmi_flags ) (•pm_entry)(); //----------------------------------------------------------- // Процедура вывода символа на экран в защищенном режиме void pm_putch(int chr) { // Структура для вызова прерывания должна // оытв определена как статическая static HM_INT_CALL regs. static PM. INT CALL far ’pregs = (void far ’) 0, // В первый раз инициализируем структуру и указатель на нее if (1pregs) { pregs = &regs; memset(pregs, 0, sizeof(RM_INT_CaLL)); regs.eax = 0x0200; regs edx = chr; // Вызываем прерывание DOS для вывода символа rm_int(0x21, 0, pregs); //------------------------------------------------------------- // Процедура вывода строки на экран в защищенном режиме void pm_puts(char ’str_ptr) { while (’str_ptr) { pm_putch(’str ptr) ; str_ptr*-+; ) }
Операционная система Microsoft WINDOWS 183 //---------------------------------------------- // Процедура вывода строки на экран в // в защищенном режиме, аналог функции printf!) void cdecl pin printf(const char 'fmt, ...) { char buffer[512), ’sptr=buffer; va_list marker; va_3tart(.marker, fmt); vsprintf!buffer, fmt, marker); va_end(marker); while (’sptr) pm_putch('sptr++), I // Процедура вызова прерывания реального режима int rm_int(unsigned int_number, // номер прерывания unsigned params // количество слов параметров // передаваемых через стек FM_1NT_CAI.L far 'rm_call) // адрес структуры // для вызова прерывания ( asm { push di push bx push ex mov ax, 0300h // Функция вызова прерывания mov bx, int_number mov ex, params; les di, rm_cal1 // запись в ES:DI адреса структуры int 31h // вызов сервера DPMI jc error mov ax, 0 // нормальное завершение ^mp short rm_int_end error: asm mov ax, 1 // завершение с ошибкой rm_int_end: asm pop ex asm pop bx asm pop di ) // Процедура отображает текущее состояние памяти int mi_show(void) { PMI minfo, far ‘minfoptr = cSminfo; unsigned long psize, far "psi zeptr=<!ipsize; unsigned sei; void far ‘fp; get.jni(minfoptr) ; pm_printf(” Информация об использовании памяти\п\г” ” ------------------------------------\n\r” "\r\n Размер максимального доступного блока:\t\t%ld байт” ’ДИАЛОГ-МИФИ'
184 Защищённый режим процессоров Intel 80286/80386/80486 ”\г\п Доступно незафиксированных страниц.\t\t%ld”, minfo.avail_block, minfo.max_page), pm_printf(”\rхпДиступно зафиксированных страниц \t\t%ld\r" "\n Размер линейного адресного пространства \t%ld страниц" ”\г\п Всего имеется незафиксированных страниц \t%ld" minfo max_locked, minfo 1inadr_space. minfo total_unlocked) pm_princf("\r\n Количество свободных страниц \t\t\t%ld" "\r\n Общее количество физических страниц'\t\t%ld”. minfo.free_pages, minfo tot_phys_pages), pm_printf(”\г\пСвободное линейное адресное" " пространство.\t%ld страниц \п\пРазмер файла/" "раздела для страничного обмена \t%ld страниц". minfo free_linspace, minfo size_fp); get_page_si ze(psizeptr); pm_printf("хг'.п Размер страницы\t\t\t\t%ld байт\г\п”, psize); // Выводим текущие значения регистров CS и DS asm mov sei,cs pm_printf(”\n\r CS = X04 4X, ” sei), asm mov sei,ds pm_printf(*DS = %04 4X",sel); // Выводим значение текущего приоритетного кольца fp = (void tar ') main, sei = FP_SEG(fp) 4 3; pm_printf(”\n\r Номер приоритетного кольца = %d\n\r",sei) ) // Процедура для получения информации об использовании памяти int get_mi(FMI far ‘minfo) { asm I mov ax, 0500h les di, minfo // ES DI = адрес структуры DMI int 31h jc error mov ax, 0 jmp short get_mi_end error asm mov ax, 1 get_mi_end: // Процедура для получения размера страницы памяти int get_page_size(long far ’page_size) { asm { mov ax, 0604h int 31h jc error
Операционная система Microsoft WINDOWS 185 les di, page_size // ES:DI = адрес page_size mov es [di], ex mov es.(di+2], bx mov ax, 0 jmp short gps_end ) error: asm mov ax, 1 gps_end: // Определение сегментного адреса видеопамяти unsigned crt_mode, crt_seg; int video_init(void) ( union REGS r; // Определяем текущий видеорежим г. h.ah=15; int86(0xl0,i£r ,<£r) ; crt_mode = r . h . al; if(crt_mode — MONO_MODE) crt_seg = 0xb000; else if(crt_mode == BW_80_MODE || crt_mode == COLOR_80_MODE) crt_seg = 0xb800; else { print!("ХпИзвините, этот видеорежим недопустим ”); exit(-l); ) } // Получение селектора для адресации видеопамяти char far ’vid_ptr; DESCRIPTOR d; unsigned Idtsel; int allocvideosel(void) { void far ‘fp. unsigned long addr; FP_SEG(vid_ptr) = crt_seg; FP_OFF(vid_ptr) = 0, pm_printf(” Адрес видеопамяти реального режима:\t %Fp\r\n”, vid_ptr), // Получаем свободный LDT-селектор if (! (Idtsel = get_sel())) ( pm printfC Ошибка при получении селектора").; dos_exit(-l); ) pm_printf(" Получен селектор \t\t\t%04.4X\n\r" , Idtsel); // Подготавливаем дескриптор для полученного селектора •ДИАЛОГ-МИФИ-
186 Защищённый режим процессоров Intel 80286/80386/80486 d limit = 0x2000; addr = ABSADDR(ert_seg, 0); d addr_lo = addr & 0xFFFF; d addr .hi = addr >> 16. d access accessed = 0; // не использовался d access. .read_write = 1; // разрешены чтение/запись d access conf_exp = 0, //не стек d access code - 0, // это сегмент данных d access xsystem = 1, //не системный дескриптор d access dpi = 3, // приоритетное кольцо 3 d .access present = 1 // сегмент присутствует з памяти d reserved = 0, // Устанавливаем дескриптор if (Iset_descriptor(idtsel, &d)) ( pm_printf("Ошибка при установке дескриптора"); getchO dos_exit(-l), ) // Выводим на экран адрес видеопамяти FP_SEG(Vid_ptr) = Idtsel, FF_OFF(vid_ptr) = 0, pm.printf("Адрес видеопамяти защищенного режима:\t%Fp\r\n”, vidptr), ) // Освобождение селектора видеопамяти int free_videosel(void) ( if (!sel_free(Idtsel)) { pm_printf(” Ошибка при освобождении селектора”); dos_exit(-l). ) ) // Получить один селектор в LDT unsigned get_sel(void) ( asm { mov ax. 0 // получить селектор mov ex, 1 // нужен один селектор int 31h jc error jmp short gs_end // AX содержит новый LDT-селектср ] error asm mov ax. 0 // произошла ошибка gs_end )
Операционная система Microsoft WINDOWS 187 // Установить дескриптор для LDT-селектора int set_descriptor(unsigned pm_sel, DESCRIPTOR far 'desc) [ asm ( push di push bx mov ax, 000Ch mov bx, pm_sel les di, desc int 31h jc error mov ax, 1 jmp short sd_end 1 error: asm mov ax 0 sd_end asm pop bx asm pop di } // Освободить LET-селектор int sel_free(unsigned pmodesel) { asm ( mov ax, 000111 mov bx, pmodesel int 31h jc error mov ax, 1 jmp short done error asm mov ax, 0 done: 1 // Вывод символа непосредственной записью в видеопамять void vi_putch(unsigned int х,unsigned int у,char c,char attr) { register unsigned int offset, char far "vid_ptr; offset=(y'160) + (x‘2) , vid_ptr=MK_FP(Idtsel, offset) , "vid_ptr++=c; 'vid_ptr=attr; // Вывод строки непосредственной записью в видеопамять void vi_print(unsigned int x,unsigned int y.char ’s.char attr) 'ДИАЛОГ-МИФИ’
1ВИ Защищённый режим процессоров inte: 80386/80388/80485 while!’s) vi_putch(x++, у 's++, attr), ) // Вывод сообщения непосредственной записью в видеопамять void vi_hello_msg(void) ( vi_print(0, 0, ” Демонстрация работы с интерфейсом ” "DF4T ‘ | (С) Frolov А V , 1992 '', 0x30); } Драйверы, резидентные программы и WINDOWS В этом разделе, как и в следующем, мы не будём ничего говорить о защищён- ном режиме работы процессора. Мы рассмотрим здесь некоторые особенности, которые необходимо учитывать при разработке резидентных программ и драйве- ров, работающих совместно с WINDOWS. Очень часто резидентные программы или драйверы перехватывают аппаратное прерывание клавиатуры и отслеживают коды нажимаемых клавиш, выполняя те или иные действия при нажатии заданных комбинаций. Например, драйвер ’’сек- ретного” диска Norton DISKREET может при нажатии заданной комбинации клавиш блокировать доступ к "секретному” диску, экрану и клавиатуре. Так как WINDOWS в расширенном режиме использует собовенную систему клавиатурного ввода/вывода, основанную на очередях сообщений, а также реа- лизует концепцию виртуальных машин, нажатие активизирующих резидентную программу комбинаций клавиш в неподходящий момент может не привести к желаемому результату и даже стать причиной "зависания” системы Есть два возможных решения этой проблемы Во-первых, можно запретить за- пуск WINDOWS, если активна резидентная программа или драйвер, не способ- ные работать совместно с WINDOWS. Во вторых, на время работы WINDOWS можно запретить выполнение резидентной программой или драйвером специфи- ческих функций, несовместимых с WINDOWS (.например, запретить активиза- цию резидентной программы при нажатии комбинации клавиш) Перед запуском WINDOWS и перед её завершением вызываются соответст- венно функции прерывания INT 2Fh 1605h и 1606h. Ваша резидентная програм- ма или драйвер могут подготовить собственные обработчики для этих прерыва- ний и отслеживать моменты запуска WINDOWS и завершения её работы. Функция 1605Й вызывается при запуске WINDOWS: Регистры при вызове прерывания. АХ 1605h ES:BX ООООНОООО.т DS SI OOOOh.OOOOn CX OOOOh
Операционная система Microsoft WINDOWS 189 DX Флаги: бит 0*0, если выполняется инициализация WINDOWS в расширенном режиме; бит 0=1, если выполняется инициализация DOS-экстендера "Microsoft 286 DOS extender" (используется в стандартном режиме работы WINDOWS); биты 1 - 15 зарезервированы, их содержимое не определено. Регистры перед возвратом из прерывания: СХ 0000Н, если WINDOWS может продолжать инициализацию; СХ <> 0, если запуск WINDOWS недопустим. Функция 1606h вызывается при завершении WINDOWS в расширенном или стандартном режиме: Регистры при вызове прерывания- АХ 1606h DX Флаги: бит 0 = 0, если выполняется завершение WINDOWS, работавшей в расширенном режиме; бит 0=1, если выполняется завершение DOS-экстендера "Microsoft 286 DOS extender”; биты 1-15 зарезервированы, их содержимое не определено. Обработчик функции 1605h может выполнить необходимые действия, связан- ные с модификацией алгоритма работы резидентной программы или драйвера, а также при помощи соответствующей установки регистра СХ может разрешить или запретить запуск WINDOWS. Обработчик функции 1606h получает управление при завершении работы WINDOWS и может восстановить прежний алгоритм работы критичной к WINDOWS резидентной программы или драйвера. Приведённая ниже резидентная программа перехватывает прерывание INT 2Fh и отслеживает фунции 1605h и 1606b, вызавая сообщение и ожидая на- жатия на любую клавишу при запуске и завершении работы WINDOWS: Листинг 22. Контроль запуска WINDOWS. Файл wintsr asm .MODEL tiny . CODE .STARTUP jmp begin old_int2Fh_off dw 0 ; Адрес старого обработчика old_int2Fh_seg dw 0 ; прерывания 2Fh ’ДИАЛОГ-МИФИ’
190 Защищённый режим процессоров Intel 80286/80386/80486 ; Сообщение, которое будет вйдано на экран при запуске WINDOWS msgwin db ’WINDOWS Started Press any key.. msg_win_off dw offset msg_win ; Сообщение, которое будет выдано на экран ; при завершении WINDOWS msg_winl db 'WINDOWS Ended. Press any key $’ msg_winend_off dw offset msg_winl ; Новый обработчик прерывания 2Fh нужен для проверки наличия ; программы в памяти при ее запуске для предохранения ; от' повторного запуска new_int2Fh proc far cmp ax,0FF00h jz installed cmp ax,1605h jz winstart cmp ax,1606h jz winend jmpdword pt-r cs: old_int.2Fh_of f winstart. ; запуск WINDOWS push ax push bx push ex push dx push ds mov dx,cs:msg_win_off mov ah,9 push cs pop ds int 21h mov ax,0 int 16h pop ds pop dx pop ex pop bx pop ax jmp dword ptr cs:old_int2Fh_off winend: ; завершение WINDOWS push ax push bx push ex push dx push ds mov dx,cs msg_winend_off mov ah,9 push cs pop ds int 21h mov ax,0 int 16h
Операционная система Microsoft WINDOWS 191 pop ds pop dx pop ex pop bx pop ax jmp dword ptr cs:old_int2Fh_off , Если код функции 0FF00h, то возвращаем ; в регистре АХ значение 00FFh. Это признак ; того, что программа уже загружена в память installed: mov ax,00FFh iret new_int2Fh endp ; Точка входа в программу , В этом месте начинается выполнение программы begin proc ; Проверяем, не загружена ли уже программа в память mov ax,0FF00h int 2Fh cmp ax,00FFh jne first_start mov dx,offset msg_loadl mov ah,9 int 21h .EXIT , Первоначальный запуск программы first_start: ; Запоминаем адрес старого обработчика прерывания 2Fh mov ax,352Fh int 21h mov cs:old_int2Fh_off,bx mov cs:old_int2Fh_seg,es push cs pop ds ; Выводим сообщение ; Выводим сообщение mov dx,offset msg_load mov ah,9 int 21h mov dx,OFFSET new_int2Fh mov ax,252Fh int 21h ; Завершаем программу и оставляем резидентно , в памяти часть программы, содержащую новые ; обработчики прерываний mov dx,OFFSET begin int 27h ’ДИАЛОГ-МИФИ'
192 Защищённый режим процессоров Intel 8С286/80386/80486 begin endp msg_load db Резидентная программа WTNTSR загружена®’ msg_loadl db ’Резидентная программа WTNTSR уже загружвна®' end Следующая резидентная программа работает аналогично, но она запрещает запуск WINDOWS. Попробуйте, запустив предварительно программу NOWINTSR, запустить WINDOWS и посмотрите, что из этого получится. Листинг 23. Запрет запуска WINDOWS. , Файл nowintsr.asm .MODEL tiny CODE STARTUP jmp begin old_int-2Fh_off dw 0 ; Адрес старого обработчика old_int2Fh_seg dw 0 , прерывания 2Fh ; Сообщение, которое выдается при запуске WINDOWS msg win db ’NOWINTSR несовместима c WINDOWS. Нажмите любую клавишу ,$’ msg_win_off aw offset msg_win , Сообщение, которое выдается при завершении WINDOWS msg_winl db 10 13 'WINDOWS Ended Press any key.. msg_winend_off aw offset msg_winl Новый обработчик прерывания 2Fh нужен лля проверки наличия . программы в памяти при ее запуске для предохранения ; от повторного запуска new_int2Fh proc far cmp ax,0FF00h jz installed cmp ax,1605b jz winstart cmp ax,1606b jz winend jmp dword ptr cs:old_int2Fh_off wins tart push ax push bx push ex push dx push ds
Операционная система Microsoft WINDOWS 193 mov dx,es:msg_win_off mov ah,9 pash cs pop ds int 21h mov ax 0 int 16h pop ds pop dx pop ex pop bx pop ax mov cx,0ffh jmp dword ptr cs:old_int2Fh_off winend push ax push bx push ex push dx push ds mov dx,cs msg_winend_off mov ah, 9 push cs pop ds int 21h mov ax.0 int 16h pop ds pop dx pop ex pop bx pop ax jmp dword ptr cs.old_int2Fh_off Если код Функции 0FF00h, то возвращаем в регистре АХ значение 00FFh Это признак , того, что программа уже загружена в память insta1 led. mov ax,00FFh iret new_int2Fh endp Точка входа в программу begin proc Проверяем не загружена ли уже программа в память nov ах.0FF00h int 2Fh 'ДИАЛОГ-МИФИ'
194 Защищённый режим процессоров Intel 80286/80386/80486 cmp ax,00FFh jne first_start mov dx,offset msg_loadl mov ah,9 int 21h EXIT , Первоначальный запуск программы first_start. ; Запоминаем адрес старого обработчика прерывания 2Fh mov ax,352Fh int 21h mov cs:old_int2Fh_off,bx mov cs:old_int2Fh_seg,es push cs pop ds ; Выводим сообщение mov dx,offset msg_load mov ah,9 int 21h mov dx,OFFSET new_int2Ph mov ax,252Fh int 21h ; Завершаем программу и оставляем резидентно в памяти часть ; программы, содержащую новые обработчики прерываний mov dx,OFFSET begin int 27h begin endp msg_load db ’Резидентная программа NOWINTSR загружена$’ msg_loadl db 'Резидентная программа NOWINTSR уже загружена$' end Связь c WINDOWS CLIPBOARD Операционная система Microsoft WINDOWS имеет чрезвычайно удобное сред- ство обмена информацией между программами - CLIPBOARD. Это средство предназначено для обмена как текстовой, так и графической информацией. Что имеется в виду под обменом информацией? Например, вы подготавливаете рекламный проспект при помощи текстового редактора Microsoft Word for WINDOWS. В проспект необходимо поместить фо- тографию рекламируемого изделия. Используя сканер, вы считываете фотогра- фию и записываете изображение в файл. Далее полученное изображение может быть отредактировано любым графическим редактором. Выделив в графическом редакторе прямоугольный участок изображения, вы можете скопировать его в CLIBBOARD (как во временную память). Затем, переключившись на текстовый редактор, вы можете вставить в любое место текста изображение, взятое из CLIPBOARD.
Операционная система Microsoft WINDOWS 195 Вы можете также выделить часть текста и скопировать её в CLIPBOARD. За- тем этот текст может быть вставлен в другое место того же текста или вообще в другой текст, редактируемый другим редактором. Если WINDOWS работает в расширенном режиме, запустив обычную DOS- программу в окне, вы можете выделить любую часть экрана и скопировать её в CLIPBOARD. Затем содержимое CLIPBOARD можно вставить в другую DOS- программу, если она ожидает ввода с клавиатуры. Таким образом организуется перенос текстовой информации из одной DOS-программы в другую DOS-прог- рамму. Заметьте, что обе эти программы могут не знать о том, что они работают в среде WINDOWS. Однако DOS-программа, работающая в среде WINDOWS, может и сама рабо- тать с CLIPBOARD. При этом возможен обмен информацией (текстовой или графической) между DOS-программами и приложениями WINDOWS. Зная интерфейс DOS-программы с WINDOWS CLIPBOARD, вы легко сможе- те создавать DOS-программы, обменивающиеся информацией с приложениями WINDOWS. Расскажем о некоторых, наиболее полезных функциях, которые мо- гут быть использованы для работы с WINDOWS CLIPBOARD. Получишь версию WinOldAp Операционная система WINDOWS содержит специальные средства, предназна- ченные для работы под её управлением DOS-программ. В терминологии WINDOWS DOS-программы относятся к так называемым старым приложениям WINDOWS (WINDOWS Old Application). Версию драйвера WINDOWS, поддер- живающего работу с приложениями WinOldAp, можно узнать с помощью функ- ции 1700h прерывания INT 2Fh: Регистры на входе: АХ 17006. Регистры на выходе: АХ 1700h, если данная версия WinOldAp не поддерживает работу с CLIPBOARD. Если АХ не равно 1700h, то AL = верхнее значение версии (major version), АН = нижнее значение версии (minor version). Открыть CLIPBOARD Перед выполнением любой операции с CLIPBOARD необходимо открыть CLIPBOARD (по аналогии с обычным файлом): Регистры на входе: АХ 17016. Регистры на выходе: АХ 0, если CLIPBOARD уже открыт; не равно 0, если операция успешно выполнена. •ДИАЛОГ-МИФИ’
196 Защищённый режим процессоров Intel 80286/80386/80486 Очистить CUPBOARD С помощью этой функции можно удалить данные из CLIPBOARD: Регистры на входе: АХ 1702b. Регистры на выходе: АХ 0, если при выполнении операции произошла ошибка; не равно 0, если операция успешно выполнена. Записать данные в CUPBOARD С помощью этой функции DOS-программа может выполнить запись данных в WINDOWS CLIPBOARD. Регистры на входе: АХ 1703b DX Формат данных, записываемых в CLIPBOARD: 01 h текст; 02h графика в формате bitmap; 03b графика в формате metafile picture; 04h SYLK; 05h DIF; 06h графика в формате TIFF; 07h текст в кодировке OEM ES:BX Указатель на записываемые данные SI:CX Длина записываемых данных. Регистры на выходе: АХ 0, если при выполнении операции произошла ошибка; не равно 0, если операция успешно выполнена. С помощью этой функции можно записывать как текстовые, так и графичес- кие данные. Операционная система WINDOWS использует отличную от принятой в DOS кодировку символов. Кодировка WINDOWS называется ANSI-кодировкой, коди- ровка DOS - OEM-кодировкой. Есди при записи текстовых данных в CLIPBOARD вы зададите кодировку OEM (записав в регистр DX значение 7)', одновременно с записью данных будет автоматически выполняться перекодиров- ка из OEM в ANSI. Пользуясь табл. 15, вы можете записывать в CLIPBOARD графические данные в формате bitmap. Таблица 15. Формат CLIPBOARD для В IT МАР-файлов Смещение, размер Описание 00h (2) тип(ООООй) 02h (2) ширина bitmap в пикселах 04h (2) высота bitmap в пикселах
Операционная система Microsoft WINDOWS 197 06h (2) количество байт на строку 08h (1) количество цветовых планов 09h (1) количество цветовых битов в пикселе OAh (4) указатель на начало данных OEh (2) ширина в 0.1 mm 10b (2) высота в 0.1 mm 12h графические данные Исчерпывающую информацию о форматах графических файлов WINDOWS вы можете получить из документации, поставляемой Microsoft для разработчиков приложений. Получить размер CUPBOARD Размер данных, записанных в CLIPBOARD, можно узнать с помощью следую- щей функции: Регистры на входе: АХ 1704h DX Формат данных: 01 h текст; 02h графика в формате bitmap; 03h графика в формате metafile picture; 04 h SYLK; 05h DIF; 06h графика в формате TIFF; 07h текст в кодировке OEM. Регистры на выходе: DX:AX 0, если CLIPBOARD не содержит данных в указанном формате; размер записанных данных, включая заголовки. Прочитать данные из CUPBOARD Регистры на входе: АХ 1705h DX Формат данных, читаемых Из CLIPBOARD: 01 h текст; 02h графика в формате bitmap; 03h графика в формате metafile picture; 04h SYLK; 05h DIF; 06h графика в формате TIFF; 07h текст в кодировке OEM ES:BX Указатель на буфер для читаемых данных. ’ДИАЛОГ-МИФИ'
198 Защищенный режим процессоров intel 80286/80388/80486 Pei истры на выходе: АХ 0. если при выполнении операции пре изошла ошибка; не равно 0, если операция успешно выполнена. Закрыть CUPBOARD После выполнения записи необходимо закрыть CLIPBOARD (точно так же, как вы закрываете Файл) Для того чтобы закрыть CLIPBOARD, вы можете ис пользовать следующую функцию: Регистры на входе: АХ 17О8п. Регистры на выходе: АХ О, если произошла ошибка; не равно 0, если операция успешно выполнена. Установить размер данных, записанных в CUPBOARD После записи данных в CLIPBOARD программист может ограничить размер CLIPBOARD: Регистры на входе: АХ 1709h SI:CX Размер данных в байтах. Регистры на выходе: DX:AX Размер максимального доступного участка памяти. Критическая секция DOS-программа, работающая на виртуальной машине WINDOWS, может гре- менно запретить переключение задач, захватив процессор н монопольное поль- зование. Для этого она должна вызвать функцию 1681h прерывания INT 2Fh. Параметры задавать не надо. Про программу, захватившую процессор, говорят, что она вошла в критичес- кую секцию. Для выхода из критической секции и возобновления работы диспетчера задич WINDOWS программа должна вызвать функцию 168211 прерывания INT 2Fh. Пример программы для работы с CUPBOARD Приведённая ниже программа демонстрирует запись в CLIPBOARD из DOS программы, а также вход в критическую секцию и выход из неё. Вначале программа убеждается в том, что она запущена под управтечис* WINDOWS, работающей в расширенном режиме. Только в этом случае доступны функции для работы с CLIPBOARD. Цалее. протрамми демонстрирует блокировку механизма переключения задач при входе в критическую секцию. После этого проверяется доступность CLIPBOARD
Операционная система Microsoft WINDOWS 199 Если CLIPBOARD доступен, программа проверяет, есть ли в нём текстовые данные. Если текстовые данные есть, они читаются из CLIPBOARD и выводятся на экран. Затем CLIPBOARD очищается и в него записывается тестовая строка, состоящая из,латинских букв и символов кириллицы (для проверки выполнения перекодировки из OEM в ANSI). После записи строки программа устанавливает размер CLIPBOARD и закры- вает его. Далее вы можете запустить приложение WINDOWS ’’Clipboard” и по- смотреть результат! Листинг 24. Работа с WINDOWS CLIPBOARD и критической секцией. Файл windos.c #include <dos.h> #include <stdio.h> ^include cmalloc h> char buf[2048], far 'fptr = buf; char msg{I - "String for storing(flna записи) to WINDOWS clipboard\n\n\n”; void main(void) { union REGS inregs, outregs; struct SREGS segregs; unsigned long clipbrd_size, i; printf("\п\пРабота c WINDOWS CLIPBOARD ” и критической секцией\п(С) Frolov A. 1992\n\n”); // Проверяем, работает ли программа под управлением // WINDOWS в расширенном режиме. inregs.х.ах = 0x1600; int86( 0x2f, <£inregs, fioutregs); if (outregs.h.al = 0) { printf(”\пТребуется расширенный режим WINDOWS!\n”); exit(-i); ) // Выводим на экран версию WINDOWS printf("Версия WINDOWS - %d.%d\n", outregs.h.al, outregs h ah); // Определяем и выводим на экран идентификатор виртуальной // машины, на которой работает данная программа. inregs.х.ах = 0x1683, int86( 0x2f, fiinregs, <Soutregs); printf("Виртуальная машина - VM%d\n", outregs x.bx); // Входим в критическую секцию. До выхода из нее // переключение задач в WINDOWS блокировано. inregs,х.ах = 0x1681, int86( 0x2f, fiinregs, <fioutregs); printf("\п\пВошли в критическую секцию.\п” "Попробуйте переключить задачу клавишами <ALT-TAB> , \п’’- 'ДИАЛОГ-МИФИ'
200 Защищённый режиы процессоров Intel 80286/80386/80486 "затем нажмите любую другую клавишу для выхода\п” "из критической секции\п”), // После наждтия на любую клавишу выходим // из критической секции getch(); inregs.х ах - 0x1682; int86( 0x2f , ^inregs, fioutregs); printf("Вышли из критической секцииХп”); // Проверяем доступность CLIPBOARD Если доступен, // выводим версию драйвера WINDOWS, использующегося // для поддержки DOS-программ, - WINOLDAP. inregs.х.ах = 0x1700; int86( 0x2f, Ainregs, «outregs); if(outregs.x.ax == 0x1700) ( printf("XnClipboard недоступна”); exit(-l); ) else printf("ХпВерсия WINOLDAP - %d.%d", outregs.h.al, outregs.h.ah); // Открываем CLIPBOARD inregs.x.ax =0x1701; int86( 0x2f, «inregs, «outregs), if(outregs.x.ax = 0Х0Й00) ( printf (’’ХпОшибка при открытии Clipboard"); exit(-l); ) // Получаем объем данных, находящихся в CLIPBOARD. // Регистр DX равен 1, следовательно, мы будем работать // с текстовыми данными. inregs.х ах = 0X1704; inregs.x.dx = 0x01; int86( 0x2f, «inregs, «outregs), // Вычисляем объем данных clipbrd_size = outregs.x.dx << 161; clipbrd_size += outregs.x.ax; if(clipbrd_size = 0L) printf("XnClipboard пуст"), else printf("ХпОбъем данных в Clipboard: %lu\n", clipbrd_size); // Получаем данные из CLIPBOARD. В регистре DX задаем значение // 7, что соответствует тексту в кодировке OEM. При этом // в процессе передачи данных выполняется перекодировка // из представления ANSI (используется в WINDOWS) // в представление OEM (используется в DOS) inregs.х.ах = 0x1705; inregs.x.dx = 0x07; segregs es = FP_SEG(fptr); inregs.x.bx = FP_OFF(fptr); int86x( 0x2f, «inregs, «outregs, «segregs) , // Выводим содержимое CLIPBOARD, если там что-нибудь есть.
Операционная .система Microsoft WINDOWS 201 if(outregs.x.ax — 0) printtf(”\nB Clipboard ничего нет!"); else ( printf("Содержимое Clipborad:\n“); j for(i=01; i < clipbrd_size; i++) putch(buf(i)); // Очищаем CLIPBOARD inregs.x ax = 0x1702; int86( 0x2f, Ainregs, fioutregs); // Записываем в CLIPBOARD текстовые данные в кодировке OEM inregs.х.ах = 0x1703; inregs.x.dx = 0x07; inregs.x.si = 0x00; inregs.x.ex = strlen(msg); fptr = msg; segregs.es = FP_SEG(fptr); inregs.x.bx = FP_OFF(fptr); int86x( 0x2f, fiinregs, efioutregs, fisegregs); if(outregs.x.ax == 0) { printf(”\пОшибка при записи в Clipboard”); exit(-l); ) // Устанавливаем размер CLIPBOARD, равный // длине записанной в него строки inregs.х.ах - 0x1709; inregs.х.si = 0x00; inregs.х.ex = strlen(msg); int86( 0x2f, fiinregs, Aoutregs); // Закрываем CLIPBOARD inregs x.ax = 0x1708; int86( 0x2f, &inregs, cSoutregs); exit(0); ) ‘ДИАЛОГ-МИФИ'
Приложение 1 Регистр EFLAGS В этой таблице описан формат регистра флагов для процессоров i80386 и 180486 (регистр флагов процессора i80286 называется FLAGS и представляет со- бой младшее 16-разрядное слово регистра EFLAGS): Номер бита Назначение 0 - CF 1 - 1 2 - PF 3 - 0 4 - AF 5 - 0 6 - ZF 7 - SF 8 - TF 9 - IF 10 - DF И - OF 12-13 - IOPL 14 - NT 15 - 0 16 - RF 17 - VM Флаг переноса Зарезервировано и равно 1 Флаг чётности Зарезервировано и равно 0 Флаг вспомогательного переноса Зарезервировано и равно 0 Флаг нуля Флаг знака Флаг ловушки Флаг разрешения прерываний Флаг направления Флаг переполнения Уровень привилегий ввода/вывода Флаг вложенной задачи Зарезервировано и равно 0 Флаг возобновления (только i80386 и 180486) Флаг режима виртуального процессора 8086 (только i80386 и 180486) 18 - AC 19-31 - 0 Флаг проверки выравнивания (только 180486) Зарезервировано и равно 0 Приложение 2 Управляющие регистры процессора i80386 Регистр Назначение CR0 CR1 CR2 CR3 Регистр состояния процессора Зарезервирован Линейный адрес отказа страницы Базовый адрес каталога страницы
Приложение 3 Формат регистра CRO процессора i80386 Номер бита Назначение 0 - РЕ 1 - МР 2 - ЕМ 3 - TS 4 - ЕТ 5-14 15 - PG Включение защищённого режима работы процессора Присутствие сопроцессора Эмуляция сопроцессора Переключение задачи Тип сопроцессора - 18G287 или 180387 Зарезервировано Включение механизма трансляции страниц Приложение 4 Формат регистра CR0 процессора 180486 Номер бита Назначение 0 - РЕ 1 - МР 2 - ЕМ 3 - TS 4 - ЕТ 5 - NE Включение защищённого режима работы процессора Присутствие сопроцессора Эмуляция сопроцессора Переключение задачи Тип сопроцессора - 180287 или 180387 Числовая ошибка. Разрешает обработку ошибок при операциях с плавающей точкой 6-15 16 - WP Зарезервировано Защита записи. При установке этого бита страницы пользователя защищены от записи в режиме супервизора 17 18 - AM Зарезервировано Бит маски выравнивания. Этот бит разрешает или запрещает контроль выравнивания операндов команд в памяти. Контроль выравнивания разрешён только для программ, работающих в третьем кольце, при условии что установлен бит AM 19-28 29 - NW Зарезервировано Разрешение сквозной записи Используется в механизме управления кэшированием 3b - CD Запрещение кэширования. Если этот бит установлен, внутреннее кэширование запрещено 31 - PG Включение механизма трансляции страниц "ДИАЛОГ-МИФИ"
Приложение 5 Формат регистра CR3 процессора i80486 Номер бита Назначение 0-2 3 - PWT Зарезервировано Прозрачность записи на уровне страниц. Используется для управления записью во внешний кэш 4 - PCD Запрещение кэширования на уровне страниц. Используется для управления работой внешнего кэша 5-31 - PBDR Базовый регистр каталога страниц
Приложение 6 Системные команды процессоров i80286/i80386/i80486 Системные команды предназначены для использования главным образом в модулях операционных систем G модулях ядра операционной системы, в драй- . верах и т. д ) Некоторые из перечисленных ниже команд полезны и при разра- ботке прикладных программ, работающих в защищённом режиме. Мы приведём только краткий перечень основных системных команд, подробности вы можете узнать из справочных руководств по процессорам (см список литературы). Как правило, системные команды могут использовать только те программы, которые выполняются в нулевом привилегированном кольце. ARPL Коррекция поля привилегий инициатора запроса в селекторе Эта команда используется системными модулями для проверки уровня запра- шиваемых привилегий в передаваемых им в качестве параметров селекторов. Прикладная программа не должна запрашивать привилегии, превышающие её собственные. Первый операнд команды - 16-разрядный регистр или слово памяти, содержа- щие значение проверяемого селектора. Второй операнд - регистр, в который за- писано содержимое CS прикладной программы Если команда не изменяла- уровень привилегий, в регистре FLAGS (EFLAGS для процессоров i80386 и >80486) устанавливается флаг нуля. В противном слу- чае этот флаг сбрасывается. Пример использования команды. mov dx, cs mov ax, TESTED_SELECTOR arpl dx, ax CUTS Сброс флага TS переключения задачи в регистре CR0 Каждый раз при переключении задачи флаг TS устанавливается в 1. Команда CLTS позволяет сбросить этот флаг. ДАЛ Загрузка байта прав доступа Для процессора i80286 команда LAR загружает в первый операнд (регистр) байт доступа дескриптора, выбираемого вторым операндом. Второй операнд яв- ляется селектором, указывающим на используемый дескриптор 'ДИАЛОГ МИФИ'
206 Защищённый режим процессоров Intel 80286/80386/80486 В процессорах i80386 и 180486 для первого операнда команда LAR использует 32-разрядный регистр. Кроме байта прав доступа в этот регистр заносятся биты типа сегмента (9 - 11), DPL (14), бит присутствия (15), бит дробности (23). LGDT Загрузка регистра GDTR Команда выполняет инициализацию регистра GDTR, указывающего располо- жение в памяти и размер глобальной таблицы дескрипторов. LIDT Загрузка регистра IDTR Команда выполняет инициализацию регистра IDTR, указывающего располо- жение в памяти и размер дескрипторной таблицы прерываний. LLDT Загрузка регистра LDTR Команда выполняет инициализацию регистра LDTR, указывающего располо- жение в памяти и размер локальной таблицы дескрипторов. LMSW Загрузка слова состояния процессора С помощью этой команды можно выполнить загрузку младшего слова регист- ра CR0 из регистра - операнда команды. Эта команда может использоваться для переключения процессора в защищён- ный режим. Обратного переключения эта команда не обеспечивает (даже для процессоров i80386 и 180486). LSL I Загрузка предела сегмента Команда имеет два операнда. Граница сегмента, селектор которого использу- ется в качестве второго операнда (задаётся в регистре), загружается в регистр, указанный в качестве первого операнда. LTR Загрузка регистра задачи Команда предназначена для загрузки регистра TR - регистра задачи. Загрузка этого регистра не приводит к переключению задачи. MOV Загрузка системных регистров Для процессоров i80386 и ,80486 в качестве операндов обычной команды MOV допустимо (на нулевом уровне привилегий) указывать системные регистры
Системные команды процессоров 207 CRO, CR2, CR3, DRO, DR1, DR2, DR3, DR6, DR7, TR6, TR7. Команда MOV может быть использована процессорами i80386 и 180486 для возврата процессора из защищённого режима в реальный. SGDT Запись в память содержимого регистра GDTR Команда позволяет узнать текущее содержимое регистра глобальной дескрип- торной таблицы GDTR, обычно её используют в системных отладчиках. SIDT Записать в память содержимое регистра IDTR Команда позволяет узнать текущее содержимое регистра глобальной дескрип- торной таблицы прерываний IDTR, используется в системных отладчиках. SLDT Записать в память содержимое регистра LDTR Команда позволяет узнать текущее содержимое регистра локальной дескрип- торной таблицы LDTR, используется в системных отладчиках. SMSW Записать слова состояния процессора Команда записывает в память или 16-битовый регистр младшее слово регистра CR0 и может быть использована в системных отладчиках. SIR Запись регистра задачи Команда записывает текущее содержимое регистра задачи TR в 16-разрядную ячейку памяти или 16-разрядный регистр. Может использоваться в системных отладчиках. VERR Проверить сегмент на возможность чтения. VERW Проверить сегмент на возможность записи С помощью этих двух команд можно проверить соответственно доступность выбранного селектором сегмента на чтение и запись. Если операция чтения или записи доступна, флаг нуля ZF устанавливается в единицу, в противном случае он сбрасывается в нуль. Основное назначение этой команды - предотвратить возникновение исключе- ния по защите памяти при попытке обращения к сегменту. Прежде чем выпол- нять обращение, программа может проверить доступность сегмента и сделать со- ответствующие выводы. ‘ДИАЛОГ-МИФИ-
Приложение 7 Недокументированная команда 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. Таблица 16. Формат буфера для команды LOADALL Адрес Регистры процессора 800h-805h Не используется 8O6h-8O7h Слово состояния процессора MSW (Machine Status Word) 808h-815h He используется 816b-817h Регистр задачи TR (Task Register) 818h-819h Регистр флагов 81Ah-81Bh Регистр IP (Instruction Pointer)
Недокументированная команда LOADALL 209 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) Для ускорения доступа к содержимому дескрипторных таблиц в процессоре имеются так называемые теневые регистры, или регистры кэша дескрипторов. Когда процессор загружает селектор в сегментный регистр, автоматически выпо- лняется загрузка соответствующего регистра кэша дескриптора. Не существует какого-либо иного способа загрузить кэш дескриптора явно из программы с по- мощью обычных команд. Однако вы можете воспользоваться для этого командой LOADALL, подготовив в описанном выше буфере необходимые значения. Формат кэша дескриптора приведён в табл. 17. Таблица 17. Формат кэша дескриптора. Смещение поля Назначение паля 0 - 2 3 24-битовый базовый адрес сегмента Байт доступа, его формат полностью аналогичен формату байта доступа дескриптора, за исключением бита присутствия. На месте этого бита находится бит VALID. Если этот бит сброшен в 0, при попытке использовать дескриптор для адресации памяти произойдёт исключение В с кодом ошибки 0 4 - 5 16-битовый предел сегмента В-Э5Ч 'ДИАЛОГ-МИФИ'
210 Защищенный режим процессора Intel 80286/80386/80486 Можно предложить следующий алгоритм использования команды LOADALL: Запретитите прерывания. Сохраните где-нибудь в буфере программы область памяти, начинающую- ся с адреса OOaOOh и имеющую длину 102 байта. Заполните буфер для команды LOADALL необходимыми значениями для всех загружаемых регистров. Базовый адрес в области кэша дескриптор^ сегмента данных должен указывать на необходимый вам участок расши- ренной памяти. Выполните команду LOADALL. Сегмент данных теперь будет указывать на область расширенной памяти. Выполните запись или чтение области расширенной памяти Восстановите базовый адрес сегмента данных в кэше дескриптора данных в буфере, расположенном по адресу 00800h. Выполните команду LOADALL ещё раз Восстановите содержимое сохранённого ранее буфера. Разрешите прерывания. При выполнении команды LOADALL -нс делается никаких проверок. Вам нео- бходимо самим позаботиться о том, чтобы загружаемые в регистры процессора значения имели какой-нибудь смысл. В противном случае состояние процессора окажется непредсказуемым. Команда LOADALL может выполняться в защищённом режиме в нулевом при- оритетном кольце. Но, к сожалению, эту команду нельзя использовать для пере- ключения процессора из защищенного в реальный режим. Процессор i80386 также имеет команду LOADALL, но её код и выполняемые функции другие.
Приложение 8 Утилита MEMOSCOP Для определения активных интерфейсов с защищённым режимом можно ис- пользовать предлагаемую утилиту MEMOSCOP. Эта утилита проверяет присутс- твие всех уровней поддержки программ, работающих в защищённом режиме или с расширенной памятью, - от BIOS до DPMI. // -MEMOSCOP*, (С) Frolov А.V., 1992 // // Файл memoscop с ♦include <stdio.h> ♦include <stdlib.h> ♦include <dos.h> void main(void) { extern int getcpu(void); unsigned cpu_type, ver; unsigned err; char ver_hi, ver_lo, verems, unsigned hostdata_seg, hostdata_size, dpini_flags; void (far -pm_entry)(); union REGS regs; struct SREGS segregs; printf(\n,MemoScop* v 1.0, (C) Frolov A.V., 1992\n” ”----------------------------------------------\n") . // Определяем тип центрального процессора. Если программа // работает на процессоре 18086, завершаем выполнение, // т. к. в этом случае интерфейсы с защищенным режимом // недоступны printf(’’Тип процессора: 80%d\n" . (cpu_type = getcpuO)); if(cpu_type = 86) { printf(”\nHa этом процессоре нам ” "работать не интересно ..’’); exit(0); } // Определяем размер доступной через прерывание INT 15h // расширенной памяти. printf(”\п---------------Уровень BIOS-----------------\п”); regs.h.ah = 0x88; int86(0xl5, <fcregs, &regs); printf( ’Размер расширенной памяти, доступной " "через INT 15: \t%d КбайтХп”, regs.х.ах), // Проверяем, установлен ли драйвер HIMEM.SYS, // если установлен, выводим его версию. printf(”\п---------------Уровень ХММ------------------\п”); •ДИАЛОГ-МИФИ’ &
212 Защищённый режим процессоров Intel 80286/80386/80486 if (XMM_Installed()) { printf("Установлен драйвер HIMEM.SYS”); ver - XMM_Version(); printf(”, версия: %4X, изменения: %4X\n”, (short)ver, (shortXver >> 16)); printf("Размер свободной расширенной памяти, ” "доступной через ХММ: %ld КбайтЧп", (long)XMM_QueryLargestFree()); printf("Общий размер расширенной памяти, доступной ’ через ХММ: \t %ld КбайтЧп”, (long)XMM_QueryTotalFree()); } else printf("ЧпДрайвер HIMEM.SYS не установлен."); printf(”\n-------------Уровень EMS/VCPI---------------\n”); // Проверяем наличие драйвера EMS/VCPI if(ems_init()) printf("Драйвер EMS/VCPI не загружен\п"); else ( printf("Драйвер EMS/VCPI загружен, ”); // Выводим номер версии драйвера if((err = ems_ver(<fiverems)) ! = 0) ( printf("ЧпОшибка %02.2X при определении " "версии EMM”, err); exit(-l); ) printf("версия EMM: %02.2X”, verems); // Определяем присутствие VCPI и его рерсию if(vcpi_ver(&ver_hi, <5ver_lo) != 0) { printf("ЧпДрайвер EMM не поддерживает VCPI\n”); exit(-l); ) printf("ЧпВерсия VCPI: %02.2X.%02.2X4n", ver_hi, ver_lo); } printf("\n---------------Уровень DPMI--------------------”). // Проверяем доступность и параметры сервера DPMI regs.x.ax - 0x1687; int86x(0x2F, <£regs, firegs, fisegregs); if(regs.x.ax != 0) ( printf("ЧпСервер DPMI не активен"); exit(-l); ) // Определяем версию сервера DPMI printf("ЧпВерсия сервера DPMI: 4t4t4t%d.%d4n”, regs.h.dh, regs.h dl); // Определяем тип процессора printf("Тип процессора:\t\t\t\t"); if(regs.h.cl = 2) printf("80286”); else if(regs.ft.cl = 3) printf(”80386” ); else if(regs.h.cl — 4) printf(”80486");
Утилита MEMOSCOP 213 // Определяем возможность работы с 32-разрядными программами dpmi_flags = regs.x.bx; printf("ЧпПоддержка 32-разрядных программ:\t”); if(dpmi_flags && 1) printf("ПРИСУТСТВУЕТ"); else printf("ОТСУТСТВУЕТ”); // Определяем размер области памяти для сервера DPMI hostdata_size - regs.х.si; printf("ХпРазмер памяти для сервера DPMI:\t\t%d байт”, hostdata_size * 16); // Определяем адрес точки входа в защищенный режим FP_SEG(pm_entry) = segregs.es; FP_OFF(pm_entry) = regs х.di; printf(”\пАдрес точки входа в защищенный режим: \t%Fp\n", pm_entry); getchO; ) /• * "Name ems_init 2.Title Функция проверяет установку драйвера EMS :.Descr Эта функция проверяет наличие драйвера EMS :.Proto ' int ems_init(void); :.Params He используются •-.Return 0 - драйвер EMS установлен; : 1 - драйвер EMS не установлен *.Sample ems_test.c ••/ int ems_init(void) ( void (_interrupt _far "EMS_driver_adr)(void); char _far "EMS driver_name; char test_nameT81; int i; EMS_driver_adr = _dos_getvect(0x67); FP_SEG(EMS_driver_name) = FP_SEG (EMS_driver_adr); FP_OFF(EMS_driver_name) = 10; for(i=0, i<8; i++) test_name(i] « EMS_driver_name(i]; if(strncmp(test_name, "EMMXXXX0”, 8) — 0) return(0); else return(l); } /"* "Name ems_ver :.Title Определение версии драйвера EMS ’.Descr Эта функция возвращает номер версии : драйвера EMS в двоично-десятичном формате. Proto int ems_ver(char ’ver); ‘ДИАЛОГ-МИФИ’
214 Защищённый режим процессоров Intel 80286/80386/80486 ‘.Params char ‘ver - указатель на байт, в который : будет записан номер версии. :.Return Номер версии драйвера EMS в формате BCD ‘.Sample ems_test.c V int ems_ver(char ‘ver) { union REGS reg; reg.x.ax = 0x4600; int86(0x67, &reg, &reg); ‘ver = reg.h.al; return(reg.h.ah); J int vcpi_ver(char 'ver_hi, char ’ver_lo) ( union REGS reg; reg.x.ax = 0xDE00, int86(0x67, &reg, &reg); ver_hi = reg.h.bh; 'ver_lo = reg.h.bl; return(reg.h.ah);
Утилита MEMOSCOP 215 Приведем исходные тексты функций, вызываемых утилитой MEMCSCOF: // ‘MEMOSGOF*, (С) Frolov А V. 1992 // Файл cpu asm DEAL MODEL SMALL P388 PUBLIC _getcpu ' CODESEG PROC _getcpu NEAP Пытаемся установить старшую тетраду регистра флагов в 0 Если программа работает на процессоре 8086, в этом байте все биты будут установлены в 1 mov dx 86 pushf pop bx and bh,0Fn push bx popf pushf pop ax and ah,0F0n cmp ah,0F0h cpu_end ; Тип процессора - 3086 Для теста на процессор 30286 пытаемся установить старшую тетроду регистра флагов в единицу Если программа выполняется на процессоре 90286, биты останутся равными нулю mov dx, 286 or bh,0F01i push bx popf pushf pop ax test ah 0F0h ja cpu_end ; Тип процессора - 80286 Чтобы отличить процессор 80386 от процессора 80488, используем бит 18 регистра флагов EFLAGS. Если программа может изменить состояние этого бита она выполняется на процессоре 80486. Иначе - используется процессор 80386. Сохраняем указатель стека mov edx,esp цимог-мифи'
216 Защищённый режим процессоров Intel 80286/80386/80486 ; Выравниваем указатель стека для предотвращения ; исключения при установке флага АС and esp.not 3 ; Копируем регистр EFLAGS в регистр ЕАХ pushfd pop eax ; Сохраняем начальное значение регистра EFLAGS mov есх.еах ; Переключаем флаг АС хог еах,40000Н ; Запишем измененное значение обратно в регистр EFLAGS push eax popfd ; Копируем регистр EFLAGS в регистр ЕАХ pushfd pop eax ; Сравниваем старое и новое значения бита АС хог еах.есх shr еах,18 and еах.1 push есх ; Восстанавливаем регистр EFLAGS popfd ; Восстанавливаем указатель стека mov esp.edx ; Если программа выполняется на процессоре 80386, регистр АХ ; содержит значение 0, а если на процессоре 80486, то 1. mov dx.386 ; Тип процессора - 80386 test ах,ах jz cpu_end mov ах,486 , Тип процессора - 80486 cpu_end: mov ах, dx ret ENDP getcpu END
Утилита MEMOSCOP 217 Для работы с функциями драйвера H1MEM.SYS используется интерфейс, опи- санный нами во втором томе "Библиотеки системного программсита”: //------------------------------------------------------ // ‘MEMOSCOP*, (С) Frolov А.V. , 1992 // // Файл xmmc . asm ; Это интерфейсный модуль для вызова функций XMS из Си. ; Текст программы рассчитан на модель памяти Small, model small,с . DATA ; В этом месте будет храниться адрес , управляющей функции ХММ XMM_Control dd ? .CODE ; Макроопределения для выполнения соглашения об ; использовании регистров в процедурах Си c_begin macro push bp mov bp.sp push si push di endm c_end macro pop di pop si mov sp.bp pop bp ret endm ; Все процедуры должны быть public public XMM_Installed public XMM_Version public XMM_RequestHMA public XMM_ReleaseHMA public XMM_GlobalEnableA20 public XMM_GlobalDisableA20 public XMM_EnableA20 public XMM_DisableA20 public XMM_QueryA20 public XMM_QueryLarges tFree public XMM_QueryTotaiFree public XMM_AllocateExtended public XMM_FreeExtended public XMM_MoveExtended public XMM_LockExtended public' XMM_UnLockExtended public XMM_GetHandleLength public XMM_GetHandleInfo public XMM_ReallocateExtended •ДИАЛОГ-МИФИ •
218 Защищённый режим процессоров Intel 80286/80386/80486 public XMM_RequestUMB public XMM_ReleaseUMB ;.Name ;.Title XMM_Installed Получение адреса управляющей функции ; . Descr Эта функция проверяет наличие драйвера HIMEM.SYS и в случае его присутствия запоминает адрес управляющей функции ;.Proto unsigned XMM_Installed(void); , Params Не используются ; Return Й - драйвер HIMEM SYS не установлен, 1 - драйвер HIMEM.SYS установлен. ;.Sample xms_test.с XMM_Installed proc near c_begin mov ax, 4300h int 2fh cmp al, 80h jne Notlnstalled mov ax, 4310h int mov mov 2fn word ptr [XMMOontrol] bx word ptr (XMM_Control+2'F->wes mov ax,1 jmp Installed Notlnstalled mov ax, 0 Installed. c_end XMM_Installed endp ,.Name ;.Title XMM_Version Определение версии доайвера HIMEM.SYS ,.Descr Эта функция определяет версию драйвера HIMEM SYS . Proto long XMM_Version(void), ;.Params He используются . Return Номер версии в младших 16 битах, номер изменений в старших 16 битах возвращаемого значения ;.Sample xms_test с XMM Version proc near push si push di
Утилита MEMOSCOP 219 xor call mov pop di pop si ret XMM_Version endp ah ah (XMM.Control] dx, bx ; Name ;.Title XMMJRequestHMA Запросить область НМА , Descr ; .Proto Эта функция пытается зарезервировать программы ооласть НМа long XMM RequestHMACunsigned space); для ;.Params .Return , Sample space - размер требуемой области для TSR-программы или драйвера, Oxffff для прикладной программы; < 0 - область НМА не назначена программе, код ошибки находится в старшем байте 0L - область НМА назначена программе. xms_test.с XMM_RequestHMA call xor dec mov ©success XMM RequestHMA proc near c_begin mov ah, 1 mov dx, [bp+4] [XMM Control) dx, dx ax jz ©success dh, bl c_end endp Name ;.Title XMM_Rel*aseHMA Освободить область НМА Descr Proto Эта функция пытается освободить область НМА long XMM ReleaseHMA(void); Params Не используются , Return , Sample < 0 - область НМА не освобождена, код ошибки находится в старшем 0L - область НМА освобождена. xms_test . с байте XMM_Relea seHMA mov proc near c_begin ah, 2 ДИАЛОГ-МИФИ
220 Защищённый режим процессоров Intel 80286/80388/80486 call xor dec mov ©successl: XMM_ReleaseHMA [XMM_Control] dx, dx ax jz ©successl dh. bl c_end endp , Name ; .Title XMM_GlobalEnableA20 Глобальное разрешение линии A20 . Descr , Proto Эта функция разрешает программе, получившей доступ к области НМА, использовать линию А20 long XMM_GlobalEnableA20(void); ; Params Не используются ;.Return Sample < 0 - линия А20 не включена, код ошибки находится в старшем байте. 0L - линия А20 включена. xms_test с XMM_GlobalEnableA20 proc near c_begin mcv ah, 3 call iXMM -Control] xor dx. dx dec ax j z ©success?, mov dh, bl @success2 c_end XMM_GlobalEnableA20 endp Name Title XMM_GlobalDisableA20 Глобальное запрещение линии A20 Descr Эта функция запрещает программе, получившей доступ к области НМА, использоьать линию^А20 Proto long XMM_GlobalDisableA20(void), Params Не используются Return < 0 - линия А20 не выключена, код ошибки находится в старшем байте. 0L - линия А20 выключена Sample xms_test с XMM_GlcbalDisableA20 proc near c_begin mov ah. 4 call tXMM_Control]
Утилита MEMOSCOP 221 xor dec dx, dx ax jz Gsuccess3 mov @success3: dh, bi c_end XMM_GlobalDisableA20 endp , Name .Title XMM_EnableA20 Локальное разрешение линии A20 ; Descr .Эта функция разрешает программе управлять областью расширенной памяти. ;.Proto long XMM_F.nableA20(void) ; ;.Params Не используются , Return < 0 - линия А20 не включена, код ошибки находится в старшем байте. 0L - линия А20 включена. , Sample xms_test.с XMM_EnableA20 proc near c_begin mov ah, 5 call [XMM_Control] xor dec dx dx ax jz @success4 mov @success4 dh, Ы c_end XMM_EnableA20 endp , Name . Title XMM_DisableA20 Локальное запрещение линии A20 ;.Descr Эта функция запрещает программе управлять областью расширенной памяти. , .Proto long XMM_DisableA20(void); ;.Params Не используются ; Return < 0 - линия А20 не выключена, код ошибки находится в старшем байте. 0L - линия А20 выключена. ;.Sample xms_test.с XMM DisableA20 proc near c_begin mov an 6 call (XMM_Control] xor dx, dx ’ДИАЛОГ-МИФИ
222 Защищённый режим процессоров Intel 80286/80386/80486 dec ax jz ©success5 mov is>success5: dh, bl c_end XMM_DisableA20 endp ; .Name ;.Title XMM_QueryA20 Проверить состояние линии A20 Descr Эта функция проверяет доступность линии А20 ;.Proto long XMM_QueryA20(void); ;.Params Не используются ;.Return < 0 - ошибка, код ошибки находится в старшем байте 0L - линия А20 выключена, 1L - линия А20 включена. ;.Sample xmS—test с ХММ_QueryA20 proc near c_begin mov call xor or ah, 7 )XMM_Control] dx, dx ax, ax jnz ©successb mov @success6: dh, bl c_end XMM_QueryA20 endp ;.Name ,.Title XMM_QueryLargestFree Определить максимальный размер блока ;.Descr Эта функция возвращает размер «максимального непрерывного блока расширенной памяти, который доступен программе ;.Proto long XMM_QueryLargestFree(void); ; Params Не используются ;.Return < 0 - ошибка, код ошибки находится в старшем байте В - размер блока. ;.Sample xms_test с XMM_QueryLargestFree proc near c_begin mov ah, 8 call (XMM Control)
Утилита MEMOSCOP 223 хог dx, dx or ax, ax jnz ©success? mov dh, bl ©success?: c_end XMM_QueryLargestFree endp ; Name XMM_QueryTotalFree ;.Title Определить размер расширенной памяти ; Descr Эта функция возвращает размер ; всей имеющейся расширенной памяти. ; . Proto long XMM_QueryTotalFree(void); ;.Params He используются ; Return < 0 - ошибка, ; код ошибки находится в старшем байте, ; >« 0 - размер расширенной памяти. ;.Sample xms_test.c XMM_QueryTotalFree proc near c_begin mov ah, 8 call IXMM_Control] or ax, ax mov ax, dx mov dx, 0 jnz @success8 mov dh, bl ©successB. c_end XMM_QueryTotalFree endp ;.Name XMM_AllocateExtended ; .Title Запросить блок расширенной памяти ;.Descr Эта функция выделяет программе блок ; расширенной памяти, в случае успеха ; возвращает индекс полученного блока. ;.Proto long XMM_AllocateExtended(unsigned space); ;.Params space - размер требуемого блока памяти ; в килобайтах; ;.Return < 0 - блок не распределен, ; код ошибки находится в старшем байте. ; > 0L - младший байт содержит индекс ; полученного блока памяти. ;.Sample xms_test.c XMM_AllocateExtended proc near c_oegin ’ДИАЛОГ-МИФИ'
224 Защищённый режим процессоров Intel 80286/80386/80486 mov ah, 9 mov dx, [bp+4] cal 1 or mov [XMM_Control] ax, ax ax, dx mov dx, 0 jnz @success9 mov @success9: dh, bl c_end XMM_AllocateExtended endp ; Name ;.Title XMM_FreeExtended Освободить блок расширенной памяти ; Descr Эта функция освобождает блок расширенной памяти, полученный функцией XMM_AllocateExtended(). ;.Proto long XMM_FreeExtended(unsigned handle); ;.Params handle - индекс освобождаемого блока памяти; ;.Return < 0 - блок не распределен, код ошибки находится в старшем байте 0L - блок освобожден. ;.Sample xms_test с » XMM_FreeExtended proc near c_begin mov ah, 0Ah mov dx, [bp+4] call xor dec [XMM_Control] dx, dx ax jz OsuccessA mov ©successA: dh, bl c_end XMM_FreeExtended endp ; .Name ; .Title XMM_MoveExtended Копировать блок расширенной памяти ; .Descr Эта функция копирует блок расширенной памяти, используя структуру struct XMM_Move: struct XMM_Move { unsigned long Length; unsigned short SourceHandle; unsigned long Sourceoffset; unsigned short DestHandle; unsigned long DestOffset;
Утилита MEMOSCOP 225 ;. Proto long XMM_MoveExtended(struct ; XMM_Move "move_descr); Params struct XMM_Move ,move_descr - ; указатель на структуру, описывающую, ; что, откуда и куда надо копировать. Return < 0 - ошибка, при копировании, ; код ошибки находится в старшем байте ; 0L - блок скопирован успешно. ;.Sample xms_test.c XMM_MoveExtended proc near c_begin mov ah, 0Bh mov si, [bp+4]; call [XMM.Control] xor dx, dx dec ax jz @successB mov dh, bl ©successB: c_end XMM_MoveExtended endp ; . Name ;.Title XMM_LockExtended Заблокировать блок расширенной памяти ; .Descr ;.Proto Функция блокирует блок расширенной памяти и возвращает 31 разряд его физического адреса long XMM_LockExtended(unsigned handle); ;.Params handle - индекс блокируемого блока памяти; ; Return » » ;.Sample < 0 - блок не заблокирован, код ошибки находится в старшем байте. > 0L - блок заблокирован, функция возвращает физический адрес блока памяти. xms_test.c 1 XMM_LockExtended proc near c_begin mov ah, 0Ch mov dx, [bp+4] call [XMM_Control] xchg ax, bx dec bx jz XMML_Success mov dh, al XMML_Success : c_end XMM_LockExtended endp ;.Name XMM_UnLockExtended •ДИАЛОГ-МИФИ"
226 Защищённый режим процессоров Intel 80286/80386/80486 Title Разблокировать блок расширенной памяти ;.Descr Функция разблокирует блок расширенной памяти ;.Proto long XMM_UnLockExtended(unsigned handle); ;.Params , handle - индекс блока памяти; ; Return < 0 - блок не разблокирован, ; код ошибки находится в старшем байте ; 0L - блок разблокирован, ;.Sample xms_test.c XMM_UnLockExtended proc near c_begin • mov ah, 0Dh mov dx, (bp+4J call [XMM_Control] xor dx, dx dec ax jz ©successC mov dh, bl ©successC: c_end XMM_UnLockExtended endp ; Name XMM_GetHandleLength ;.Title Получить длину блока расширенной памяти ;.Descr Эта функция возвращает длину блока ; расширенной памяти по его индексу ;.Proto long XMM_GetHandleLength(unsigned handle); ; Params handle - индекс блока памяти; ;.Return < 0 - произошла ошибка, ; код ошибки находится в старшем байте ; > 0L - длина блока в килобайтах. ;.Sample xms_test.с XMM_GetHandleLength proc near c_begin mov ah, 0Eh mov dx, [bp+4] call [XMM_Control] or ax, ax mov ax, dx mov dx. 0 jnz ®successD mov dh, bl esuccessD:
Утилита MEMOSCOP 227 c_end XMM_GetHandleLength endp •.Name XMM_GetHandleInfo ;.Title Получить информацию о блоке расширенной памяти Descr Эта функция возвращает общее количество ; индексов в системе и содержимое счетчика ; блокирования для заданного индекса. ; .Proto long XMM_GetHandleInfo(unsigned handle); ;.Params handle - индекс блока памяти; ;.Return < 0 - произошла ошибка, ; код ошибки находится в старшем байте. ; > 0L - младший байт - общее количество ; индексов в системе, ; старший байт - счетчик блокирования. ;.Sample xms_test.c XMM_GetHandleInfo proc near c_begin mov ah, 0Eh mov dx,. [bp+4] call (XMM_ControlJ mov _.dx, bx or ax, ax mov ax, dx mov dx, 0 jnz ©successE mov dh, bl . ©successE: c_end XMM_GetHandleInfo endp ;.Name XMM_ReallocateExtended ;.Title Изменить размер блока расширенной памяти ;.Descr Эта функция изменяет размер выделенного ; блока расширенной памяти ;.Proto long XMM_ReallocateExtended(unsigned handle, ; unsigned newsize); ;.Params handle - индекс блока памяти, ; new_size - новый размер блока памяти ; в килобайтах; , Return < 0 - блок не распределен. ; код сшибки находится в старшем байте. ; > 0L - младший байт содержит индекс ; полученного блока памяти ;.Sample xms_test.c ХММ ReallocateExtended proc near c_begin ’ДИАЛОГ-МИФИ"
228 Защищённый ражим процессоров Intel 80286/80386/80486 mov ah, 0Fh call mov dx, [bp+4] mov bx, (bp+6 j (XMM_Control) xor dx, dx dec ax mov jz ©successF dh, bl ©successF: c_end XMM_ReallocateExtended endp ;.Name XMM_RequestUMB ; .Title Запросить область UMB ;.Deacr Эта функция пытается зарезервировать для программы область UMB ; . Proto long XMM_RequestUMB(unsigned space); ;.Params space - размер требуемой области в параграфах; ;.Return < 0 - область UMB не назначена программе, код ошибки находится в старшем байте максимальный размер доступного блока в младшем слове (16 разрядов); > 0L - область UMB назначена программе, младшее слово содержит сегмент блока UMB, старший - размер выделенного блока UMB ; .Sample xms_test.с XMM_RequestUMB proc near. mov c_begin ah, 10h call mov dx, (bp+4] (XMM_Control] xchg bx, ax jz dec bx RUMB_Success RUMB_Success: XMM_RequestUMB xchg ax, dx mov dh, dl c_end endp ; . Name XMM_ReleaseUMB ; . Title Освободить область UMB ;.Descr Эта функция пытается освободить ;.Proto область UMB long XMM_ReleaseUMB(unsigned segment); ;.Params segment - сегмент освобождаемого блока UMB
Утилита MEMOSCOP 229 ;.Return » » < 0 - область UMB не освобождена, код ошибки находится в старшем байте. 0L - область UMB освобождена. ;.Sample . • * xms_test.с XMM_ReleaseUMB proc near c_begin mov ah, llh mov dx, (bp+4] call xor dec [XMM_Control] dx, dx ax jz @successl0 mov @successl0: dh, bl c_end XMM_ReleaseUMB endp END ДИАЛОГ-МИФИ
Приложение 9 Защита программ от отладки Если вы разрабатываете программное обеспечение, защищённое от несанкцио- нированного копирования, вам необходимо позаботиться о том, чтобы потен- циальные ’’взломщики" ("краккеры" и "хаккеры”) не смогли выполнить программу инсталляции иод управлением отладчика Если "взломщик” сможет "проследить” работу вашей программы, он рано или поздно разгадает ваш замы- сел и сведёт ни нет все ваши усилия по защите программы от копирования. В третьей книге первого тома 'Библиотеки системного про раммиста" мы из- лагали некоторые соображения по организации зашиты программ от несанкцио- нированного копирования. Мы, в частности, рассказали о некоторых методах за- щиты программ от отладки - использование таймера, внутренней очереди команд процессора и другие. Защищённый режим работы процессора открывает перед вами новую возмож- ность Возьмите любую программу, приведённую в этой книге, и попытайтесь запустить её под управлением какого-либо отладчика (например, попробуйте Turbo Debugger или Code View) Всё будет хорошо до тех пор, пока ваша прог- рамма не попытается загрузить регистр IDTR при помощи команды L1DT. После выполнения этой команды отладчик "зависает" и единственное средство вновь оживить компьютер нажать на кнопку сброса Причина - изменились расположение и формат дескрипторной таблицы пре- рываний. Она подготовлена для работы в защищённом режиме, но отладчик ра- ботает в реальном режиме. Поэтому обработка всех прерываний, в том числе и от клавиатуры, невозможна. Идея использования защищённого режима работы процессора при создании q программ, защищённых от несанкционированного копирования, очевидна. Ис- пользуя примеры программ, приведённые в книге, вы сможете во время работы программы инсталляции перевести процессор в защищённый режим и выполнить часть работы по инсталляции в защищённом режиме. Например, перед переключением в защищённый режим вы можете подюто- вить в памяти массив контрольной информации. Расшифровка и проверка этого массива, а также запись данных в нестандартные секторы инсталляционной дис- кеты могут выполняться в защищённом режиме При этом пользуясь обычными отладчиками невозможно определить действия, выполняемые в защищённом ре жиме Особенно если участок программы, работающий в защищённом режиме, ^шифрован. Далее процессор можно вернуть в реальный режим и продолжить процесс инс- талляции. Находясь в защищённом режиме, вы можете читать и писать секторы дискеты только используя уровень портов ввода/вывода контроллера флоппи-диска. Программирование контроллера срлоппи-диска описано в третьей книге первого I ДИАЛОГ-МИФИ
Защита программ от отладки 231 тома ’’Библиотеки системного программиста”. Обрабатывать прерывания в защи- щённом режиме вы уже умеете. Очевидный недостаток применения защищённого режима при организации за- щиты от копирования заключается в необходимости использования процессоров i80286, i80386 или 180486. Это означает, что указанный метод непригоден для компьютеров IBM PC/XT, использующих процессор 18086 или 18088. Однако в последнее время большинство программных комплексов требует на- личия в компьютере по крайней мере процессора i80286, поэтому указанным не- достатком можно пренебречь. К тому же следует учесть резкое увеличение стой- кости инсталлятора, работающего в защищённ'ом режиме, к попыткам ’’взлома”. •ДИАЛОГ-МИФИ’
СПИСОК ЛИТЕРАТУРЫ Архитектура микропроцессора 80286 Алберт Д.Д., Морс С. П. М.: Радио и связь, 1990 Книга может служить справочником по процессору i80286 и сопроцессору 180287. Приведены все необходимые теоретические сведения об архитектуре процессора, в том числе сведения о возможностях процессора при работе в защищённом режиме. Обращаем ваше внимание на ошибку, допущенную в данном издании книги в разделе, по- свящённом мультизадачное™. На рис. 5.16, б (стр. 199) расположение бита занятости В показано неправильно - этот бит находится не а нулевом разряде, а в первом. Микропроцессор 80386 Брамм Д., Брамм П. М.: Мир, 1990 В книге рассмотрены программные и аппаратные средства процессора i80386. .Приведены сведения об архитектуре процессора i80386, описаны возможности процессора при работе в защищённом режиме. В этой книге вы сможете найти подробное описание команд процессора, форматов системных областей данных и системных регистров. Приведён пример программы, сос- тавленной на языке ассемблера, переводящей процессор а виртуальный режим работы. Логическое проектирование операционных систем Шоу А. М.: Мир, 1981 Книга посвящена ероектированию операционных систем. В ней достаточно полно рассмотрены теоретические проблемы проектирования различных подсистем, входящих а операционные систе- мы. Особенный интерес представляет материал, связанный с мультизадачностью и организацией взаимодействия процессов. Проектирование операционных систем для малых ЭВМ Кейслер С. М.: Мир, 1986 Содержимое книги аналогично предыдущему. Приведены алгоритмы работы различных подсистем мультизадачных операционных систем. Как и предыдущая книга, может служить теоретическим введением в проектирование операционных систем. 32-Blt Microprocessors Editor H.J. Mitchell, Great Britain, Collins, 1986 ISBN 0-00-383067-5 Книга является сборником статей о 32-разрядных микропроцессорах. Описаны архитектура и особенности микропроцессоров с RISC-архитектурой, процессор WE32100, транспьютеры фирмы Inmos, микропроцессор i80386, Motorola 68020 и Zilog Z80000. 80386. Programmer's Reference Manual INTEL Corp., USA, 1988 Эта и следующая книги - фирменные руководства по процессорам, они необходимы тем, кто собирается разрабатывать коммерческое программное обеспечение, работающее в защищённом режиме и использующее возможности последних моделей процессоров фирмы Intel. INTEL 180486 Microprocessor Hardware Reference Manual, INTEL Corp., USA, 1990 Справочное руководство по процессору I80486. Undocumented DOS Andrew Schulman, Raymond J. Michels, Jim Kyle, Tim Paterson, David Maxey, Ralf Braun, 1991
ОГЛАВЛЕНИЕ ВВЕДЕНИЕ................................................... J.3 Глава 1 ОСОБЕННОСТИ ЗАЩИЩЁННОГО РЕЖИМА ПРОЦЕССОРА i80286...............7 Адресация памяти в реальном режиме..........................10 Адресация памяти в защищённом режиме........................13 Преобразование адресов в защищённом режиме..........13 Детальное описание схемы преобразования адресов.....15 Защита в процессоре i80286.:................................21 Кольца защиты......л................................23 Тип сегментов.......................................24 Границы сегментов...................................25 Привилегированные и чувствительные команды..........25 Межсегментная передача управления...................26 Виртуальная память в процессоре i80286......................29 Глава 2 ОБРАБОТКА ПРЕРЫВАНИЙ В ЗАЩИЩЁННОМ РЕЖИМЕ......................46 Прерывания в реальном режиме................................46 Прерывания защищённого режима...............................47 Таблица прерываний защищённого режима...............47 Исключения в защищённом режиме......................48 Обработка аппаратных прерываний.....................50 Программа, которая работает с прерываниями..................51 Глава 3 МУЛЬТИЗАДАЧНОСТЬ В ПРОЦЕССОРЕ i80286..........................76 Задача и сегмент состояния задачи...........................78 Переключение задач..........................................80 Синхронизация задач и семафоры..............................81 Пример мультизадачного монитора.............................82 Глава 4 ОСОБЕННОСТИ ПРОЦЕССОРОВ i80386 и 180486......................112 Преобразование адресов.....................................113 Обработка прерываний.......................................117 Мультизадачность...........................................117 Режим виртуального процессора 18086........................119 Переключение в защищённый и реальный режимы................120 Процессор 180486...........................................121 80286, 80386, 80486...Что дальше?.........................123 •ДИАЛОГ-МИФИ
234 Защищенный режим процессоров Intel 80286/80386/80486 Глава 5 ИЕРАРХИЯ СРЕДСТВ ДЛЯ РАБОТЫ В ЗАЩИЩЁННОМ РЕЖИМЕ..................124 Интерфейс BIOS..................................................126 Интерфейс HIMEM.SYS.............................................139 Интерфейс EMS/VCP1..............................................140 Интерфейс DPMI..................................................148 DOS-экстендеры.........................................169 Phar Lap DOS-экстендер.................................171 Виртуальная машина WINDOWS.............................175 Глава 6 ОПЕРАЦИОННАЯ СИСТЕМА Microsoft WINDOWS............................176 Использование функций DPMI.................................... 178 Драйверы, резидентные программы и WINDOWS.......................188 Связь с WINDOWS CLIPBOARD......................................-194 Приложение 1. Регистр EFLAGS......................................202 Приложение 2. Управляющие регистры процессора i80386..............202 Приложение 3. Формат регистра CR0 процессора i80386...............203 Приложение 4. Формат регистра CR0 процессора i80486.............. 203 Приложение 5. Формат регистра CR3 процессора 180486...............204 Приложение 6. Системные команды процессоров 180286/180386/180486 .205 Приложение 7. Недокументированная команда LOADALL.................208 Приложение 4. Утилита MEMOSCOP....................................211 Приложение 9. Защита программ от отладки..........................230 СПИСОК ЛИТЕРАТУРЫ.................................................232
лидиогтиФи выпускает литературу по программированию и вычислительной технике, рассчитанную на широкий круг пользователей персональных компьютеров ПРОГРАММИРОВАНИЕ В MICROSOFT WINDOWS, в 2 частях С. А. Гладков, Г. В. Фролов Учеонгт-еправочное пособие по созданию программ, работающих под управлением операционной оболочки MS-Windows 2.x, 3.x. Предметный указатель позволяет использовать книгу как справочник функций MS-Windows. Можно приобрести дискету с примерами программ. ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ АВТОЛИСП В СИСТЕМЕ САПР АВТОКАД С. А. Гладков Учебно-справочное пособие по программированию. Описываются структура языка, даются методика написания и примеры программ. Рассмотрены вопросы написания макроопределений, меню Автокада и настройки рабочей среды. Ориентировано на пользователей персональных компьютеров, работающих в области САПР. С для PC. ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ С ДЛЯ ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРОВ А. Григорьев Вып. 2. Время и звук Выл. 3. Стандартный ввод/вывод и прерывания Вып. 4. Графика на экране ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ МУЛЬТИТРАНСПЬЮТЕРНЫХ СИСТЕМ Б. Ю. Сырков, С. В. Матвеев Рассмотрены основы функционирования и использования программного обеспечения. Приведены оценки производительности транспьютера; описан язык программирования высокого уровня Оккам-2, распределенная операционная система Гелиос; особое внимание уделено средствам создания параллельных программ для мультитранспьютеров в среде Гелиос; рассмотрено программирование мультитранспьютерных систем с использованием последовательных языков высокого уровня Си, Паскаль. Фортран. Модула-2); изложение ' иллюстрировано примерами. ПРОГРАММИРОВАНИЕ В СРЕДЕ TURBO PASCAL 7.0. А. Епанешников, В. Епанешников В данном пособии описана версия 7.0 широко распространенного пакета программирования Turbo Pascal, разработанного фирмой Borland International. Приведены основные характеристики языка и среды программирования. Пособие может быть полезно как при изучении языка Turbo Pascal, так и при создании программ на этом языке.
Из серии 'БИБЛИОТЕКА СИСТЕМНОГО ПРОГРАММИСТА" Том 2. АППАРАТНОЕ ОБЕСПЕЧЕНИЕ КОМПЬЮТЕРА IBM PC, в 2 частях А. В. Фрол:а, Г. В. Фролов Подробно описан^' клавиатура, мышь таймер, часы реального времени, асинхронный адаптер, порт параллельной передачи данных, контроллер прямого доступа к памяти Внимание уделе- но использованию расширенной и дополнительной памяти Для описанных устройств приво- дится методика программирования на ьсех уровнях от использования портов ввода/вывода до высокоуровневых средств стандартных библиотек трансляторов Microsoft QuickC 2.5 и С 6 О. Книга содержит большое количество примеров, составленных на языках Ассемблера и С. Том 4. ПРОГРАММИРОВАНИЕ МОДЕМОВ А. В. Фрол та, Г. В. Фролов Посвящен средствам, используемым для связи персональных компьютеров друг с другом Приведены два типа соединений, через асинхронный порт и связь с использованием модема. Рассмотрены вопросы программирования асинхронного последовательного адаптера, описаны его порты и режимы, средства BIGS Д1Я работы с адаптером а также соответствующие функции стандартных библиотек компилятора Си. Кратко рассмотрены программы Norton Commander и FastWirs Книга содержит инструкции по установке модема на компьютере, описывает режимы работы модемов. Том 5. ТОНКАЯ НАСТРОЙКА И ОПТИМИЗАЦИЯ MS-DOS Фролов А В., Фролов Г.В. В книге описываются процедуры оптимизации, позволяющие значительно повысить произво- дительность компьютера без дополнительных затрат. Описаны процедуры оптимизации ьсех подсистем компьютера, е том числе процедуры уве личения быстродействия диска, дефра> ментации файлов, кэширования динамической компрессии и архивирования данных на диске. Приведены рекомендации по оптимальному использованию оперативной памяти Описаны приемы увеличивающие производительность работы оператора компьютера. Том 7. ЛОКАЛЬНЫЕ СЕТИ ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРОВ Монтаж сети, установка программного обеспечения А. В. Фролов, Г. В. Фртгп-'' Данное учебно-справочное пособие предназначено для тех, кто решил приступить к созданию в своей организации локальной сети персональных компьютеров, для разработчиков програм- много обеспечения локальных сетей и другого программного .обеспечения Оно будет полезно администраторам рабочих групп и системным администраторам. В первой части пособия описаны сетевые средства Novell NetWare, Novell NetWare Lite, Microsoft Windows for Workgroups Приведены рекомендации no выбору аппаратных и программных средств для создания сети, по установке, настройке и сопровождению сетевых операционных систем. К каждому тому серии ’БСП" дополнительно выпущены дискеты с текстами программ и спраьочной информацией. Эти и другие издания "ДИАЛОГ-МИФИ' можно приобрести пи адресу: Москва, ул. Москворечье, 31, корп. 2. Проезд: м. Каширская, авт. 95, 117, 162, 192, 275, 709, 740 до ост. "к-тр Мечта" (см- схему) Телефон (095) 320-43-77, факс (095) 324305*
4ИИИОГ7ИИ0И готовит к печати следующие издания: НАЧАЛА КОМПЬЮТЕРНОЙ ГРАФИКИ Е. В. Шикин и др. Книга знакомит с такими понятиями компьютерной графики, как растровые алгоритмы, геометрические сплайны, преобразования на плоскости и в пространстве и проектирование. Она дает рабочее представление об основных направлениях и методах компьютерной графики, включая способы построения реалистических изображений и удаления невидимых линий, позволит освоить базовые приемы реализации ее алг оритмов на персональных компьютерах. Предлагаемая книга содержит материал, отобранный на основе опыта чтения указанного курса. Книгу можно рассматривать как практическое руководство: в ней приводятся примеры графических задач, которые может выполнить прочитавший книгу, Она рассчитана на читателей, знакомых с элементами аналитической геометрии, линейной алгебры и языком программирования Pascal. КУРС ПРАКТИЧЕСКОЙ РАБОТЫ С СИСТЕМОЙ АВТОКАД 11 Ю. А. Крепко, В. В. Полищук Появление новых версий графического пакета Автокад побуждает нас выпустить новое учебное пособие, в котором учтены, во-первых, дополнительные возможности, которые внесены разработчиками в Автокад 11 и. во-вторых, исправлены неточности и ошибки предыдущего издания. Расширен раздел, посвященный программированию на Автолиспе. Стиль подачи материала, способ представления графических иллюстраций мы сохранили. Как и в предыдущем издании параллельно рассматривается и оригинальная (англоязычная).' и русифицированная версии. МИКРОПРОЦЕССОР I486. АРХИТЕКТУРА, ПРОГРАММИРОВАНИЕ, ИНТЕРФЕЙС В. Б. Бродим, И. И. Шагурин Книга, подготовленная при поддержке фирмы Intel, описывает архитектуру, программирование и механизмы обмена микропроцессора i486. Первая глава на примере i486 знакомит читателя с основными принципами функционирования современных высокопроизводительных 32-раэрядных микропроцессоров. Структура и режимы работы i486 описаны в общем виде. 8 последующих главах подробно рассматривается система команд, работа в реальном и защищенном режимах, механизм прерываний и сообщения об ошибках, магистральные циклы обмена, встроенные средства отладки программного обеспечения. Книга адресована как специалистам в области микропроцессорной техники, так и широкому кругу читателей, самостоятельно осваивающих згу область знаний.
В серии "БИБЛИОТЕКА СИСТЕМНОГО ПРОГРАММИСТА" Том 8. ЛОКАЛЬНЫЕ СЕТИ ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРОВ Использование протоколов.IPX, S^PX, NETBIOS А. В. Фролов, Г. В. Фролов В книге рассказывается об использовании протоколов IPX, SPX и NETBIOS в программах, предназначенных для работы в среде оболочек рабочих станций локальных сетей Novell NetWare. Приведены описания протоколов, примеры программ на языках ассемблера и Borland C++, а также другие сведения, необходимые для обеспечения корректной работы программ в локальных сетях персональных компьютеров, совместимых с IBM PC. Том 9. ЛОКАЛЬНЫЕ СЕТИ ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРОВ Работа с сервером Novell NetWare А. В. Фролов, Г. В. Фролов Книга содержит основные сведения, необходимые для использования программного интерфейса сетевой оболочки рабочей станции с серверами Novell NetWare. Прочитав книгу, вы сможете создавать программы для MS-DOS, корректно работающие с файл-сервером, разрабатывать собственные сетевые утилиты, аналогичные по назначению стандартным утилитам Novell NetWare. В книге приведено множество программ на языках С и C++ для транслятора Borland C++ Версии 3.1, описан интерфейс NetWare С Interface for DOS. который Novell поставляет разработчикам сетевых средств. Все программы проверены в MS-DOS версий 5.0 и 6.0 для Novell NetWare версий 2.2 и 3.11. АО "ДИАЛОГ-МИФИ" предлагает разместить рекламу Вашей продукции в наших изданиях по информатике, распространяемых по бсей территории СНГ. Телефоны: 320-43-55, 320-43-77 Факс: (095) 324 30 55
^ИЙИОГгИИЖИ КУРСЫ УСКОРЕННОЙ подготовки К ПРАКТИЧЕСКОЙ РАБОТЕ НА ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРАХ IBM PC УСЛОВИЯ ПРИЕМА И ОБУЧЕНИЯ • Учебный центр АО "ДИАЛОГ-МИФИ” авторизован фирмами BORLAND, SYMANTEC, AUTODESK. На курсы принимаются граждане нашей страны и иностранцы без каких-либо ограничений. Для обучения на курсах предварительной подготовки в области вычислительной техники, как правило, не требуется. • Каждый день занятий - зто трехчасовая лекция и пять чаооа индивидуальной практической работы на компьютерах IBM PC. • Продолжительность курса: две недели с отрывом от производства (5 раз в неделю). Занятия проводятся под руководством высококвалифицированных преподавателей Московского инженерно- физического института и Учебного центра (1 преподаватель - 4 слушателя). По каждому курсу имеется оригинальное пособие, подготовленное Учебным центром. Оплата производится по наличному или безналичному расчетам. Иногородним предоставляется жилье. • Окончившим курсы выдается удостоверение-сертификат. Учебный центр организует и проводит занятия на базе Заказчика. В Учебном центре для всех желающих проводятся платные консультации и принимаются платные экзамены по преподаваемым курсам с выдачей удостоверения-сертификата. ДВУХНЕДЕЛЬНЫЕ КУРСЫ Практическая работа на компьютерах семейотва IBM PC в операционной среде MS-DOS. MS-DOS для программистов (использование функций DOS и BIOS при программировании на Ассемблере). Программирование на Turbo Pascal. Программирование на Turbo С. Программирование ив С** (для начинающих). • Программирование на Turbo C++ (для знающих С). Программирование под Windows на Borland C++ Программирование на Microsoft Pascal. Программирование на Microsoft QuickPascal. • Программирование на Microsoft QuickC Практическая работа с БД Paradox. Практическая работа с электронной таблицей Quattro Pro. Практическая работа с интегрированным пакетом Reflex. Использование САПР Аатокад. • Использование электронных таблиц с деловой графикой и БД а системе Microsoft Excel (с элементами Windows). Практическая работа с интегрированным пакетом Microsoft Works. Локальные и распределенные вычислительные сети. ОДНОНЕДЕЛЬНЫЕ КУРСЫ Практичеокая работа с текстовым процессором Microsoft Word Изучение графической среды Microsoft Windows. Использование Time Line для планирования и управления проектом. Программирование на Автолисле (Автокад) Программирование на PAL (в среде СУБД Paradox). El 115409, Москва, ул. Москворечье, 31, корп. 2 Телефон: (095) 320-30-88 Телефакс: (095) 3243055
Как найти ’’ДИАЛОГ-МИФИ”: Адрес: 115409 Москва, ул. Москворечье, 31, корп. 2 Телефон: 320-43-77 (издательский отдел) Телефакс: (095) 3243055 Проезд: станция метро "Каширская” (выход к 15-ой больнице), далее автобусом (95, 117, 162, 192, 275, 709, 738, 740) или троллейбусом до остановки ”к-тр Мечта” (одну остановку). I вход в ''ДИАЛОГ-МИФИ" Торговый центр I — Каширское шоссе метро каширская МИФИ
ОБУЧЕНИЕ в учебном Центре, имеющем сертификаты фирм Boris 11 a, Symantec, Autodesk: раооте на персональных компьютерах IBM PC языкам программирования работе с новейшим прикладным программным обеспечением 320-30-88 ПРОДАЖА через собственную широкую дилерскую сеть программных продуктов ведущих зарубежных фирм Symantec, Borland Miciosoff сопровождение и поддержка программного обеспечения, включая hot line компьютерной техники фирмы Intel, магнитных носителей фирмы ЗМ * оргтехники тел. 320-32-11, 320-43-44 СЕРВИС и гаоантийное и послегарантийное обслуживание вычислительной техники гел. 320-32-55 ИЗДАНИЕ оригинальных книг и учебных пособий В области информационных технологий размещение рекламы в собственных изданиях тел. 320-43-77 Наш адрес: 115409 Москва, ул. Москворечье, 31, корп. 2 Телефакс: (095) 3243055
да вимком предлагает оригинальный программный продукт: АСУ ' КОМБАНК1' “ сетевой банковский программный комплекс. Разработан совместно с ведущими специалистами Главного Вычислительного Центра при РКЦ ЦБ России. Внедрен в ряде крупных московских банков. Более ста задач, объединенных в различные АРМы (Бухгалтера, Главного Бухгалтера, Экономиста, Операциониста, Кассира—контроллера и т. д.) 7т3 "Клиент-Банк" - пересылка платежных документов в bai гк и получение выписок по телефону. Цифровая подпись и шифровка информации Связь с бухгалтерскими программами клиента Связь с операционным днем банка. "ЛСТРЛ" - - коммуникационная программа для связи Банк--РКЦ, Клиент-Банк, Банк-Банк. Повышенная защищенность. Простота использования. АСУ “КОМБАНК” используют более 2U0 банков. Россия, 111524, г. Москва, Электродная 10, "ВИМКОМ" Телефон: 176-0928, 176-1249, 176-0560 Факс: 176-7998. e-mail: net@inia.msic.su