nedoPC.org

Electronics hobbyists community established in 2002
Atom Feed | View unanswered posts | View active topics It is currently 28 Mar 2024 05:15



Reply to topic  [ 23 posts ]  Go to page 1, 2  Next
Негативные стороны многозадачноых ОС 
Author Message
Banned

Joined: 12 Oct 2006 16:44
Posts: 608
Reply with quote
Статья одного из авторов, ненавидящего многозадачки(особенно форточки). Бьёт в десятку. Мысли автора статьи мне понравились!
Сайт автора мёртв - но страница сохранена ;)
Хотелось бы услышать мнения остальных по статье :)


22 Apr 2007 19:13
Profile
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
Вытащил текст из архива прямо сюда (убрав неработающие ссылки), а архив прибил ;)

ОТРИЦАТЕЛЬНЫЕ СТОРОНЫ МНОГОЗАДАЧНОСТИ ОПЕРАЦИОННЫХ СИСТЕМ

Существующие 32-разрядные операционные системы (ОС) непременно многозадачны. Это следствие архитектуры процессоров INTEL, которая допускает возможность использования 32-битного адреса исключительно в защищенном режиме, который в свою очередь ориентирован на многозадачную среду. Однако чаще всего все-таки компьютер работает только над одной задачей. Несколько активных приложений одновременно используются, как правило при работе в Internet (загрузка нескольких разных страниц одновременно), при обмене данными (можно переписывать большой объем файлов или форматировать дискету, одновременно работая с каким-то другим приложением). В офисных и издательских приложениях так же обычно загружается несколько задач, но активна, как правило только одна с которой и ведется работа. Остальные находятся в ожидании, не выполняя никаких полезных действий. Быстрый переход от одной задачи к другой, сохранение полного состояния неактивной в данный момент задачи, удобный обмен объектами между ними - вот несомненные удобства многозадачности. Из наиболее массовых видов работы с компьютером, вот пожалуй и все (во всяком случае автору больше ничего в голову не приходит). Большинство остальных применений вполне довольствуются одной задачей, а иногда и требуют выделения себе максимума ресурсов, что зачастую оказывается довольно проблематично. В большей степени, чем к кому-либо другому, это относиться к захватившему подавляющую долю рынка ОС - Windows во всех ее разновидностях. Максимально высвободить процессор и память под ее управлением, не всегда удается даже искушенному пользователю. Классический пример, на взгляд автора, CD-Writer. Вам доводилось видеть компьютер с CD-Writer, которым пользуются от случая к случаю (у пишущих постоянно, с ним обычно все в порядке). Ему, как правило сопутствует куча угробленных дисков (не включающая то, что уже успели выкинуть) и способная привести в восторг любого производителя лазерных болванок. По наблюдениям автора, количество произведенных дисков намного превосходит количество записанных. Так вот, CD-Writer не виноват, заслуга в этом, несомненно, Windows, который хоть и стимулирует производителя (кстати не нашего), но автору как-то ближе интересы потребителя, каковым он сам и является. Грозное предупреждение о необходимости выгрузки всех активных приложений, появляющееся на экране при запуске любой пишущей программы, лишь снимает возможные претензии к поставщику софта, но не избавляет пользователя от вынужденных экспериментов по поиску все еще чего-то работающего параллельно с пишущей программой, результатом которого является лишь наполнение дисками мусорной корзины (не виртуальной, а вполне реальной) с одновременным освобождением собственного кармана от отягощающих его денежных знаков. Проблема в том, что заниматься записью дисков приходиться под управлением ОС предназначенной совершенно для других целей и никакой альтернативы к сожалению нет. Все упирается в драйвера. Они поставляются только для многозадачных систем, ибо однозадачных просто не существует.

А кстати, почему???

Так-таки уж сложно создать нечто подобное старому доброму DOS, но только с 32-разрядным ядром, выделяющее все ресурсы исключительно для одной задачи. Теоретических препятствий к этому нет, есть практические и главное из них BIOS, и ставшая практически закрытой архитектура для работы в 32-битном режиме. Для семейства PC, изначально проектировавшихся как открытая архитектура, BIOS был великолепным решением. Он брал на себя помимо функции начальной загрузки системы, еще и большую часть работы с периферией, которая могла иметь отличия у различных производителей и фактически вводил стандарт для взаимодействия программ и периферии. У компьютеров, с которыми приходилось работать, до появления PC в нашей стране, был только загрузчик. Созданный для 16-разрядного однозадачного компьютера, BIOS без существенных изменений остался таковым и по сей день. Уже давно пройден 32-разрядный барьер, в перспективе маячат 64 разряда, а поставляющаяся с компьютером встроенная система ввода-вывода остается архаично 16-разрядной, какой уж десяток лет. Казалось бы, чего проще взять список функций выполняемых BIOS, удалить те из них, которые стали на сегодняшний день анахронизмом, присвоить оставшимся новые номера из числа свободных, определить передаваемые и возвращаемые параметры с учетом 32-битной архитектуры и изменений накопившихся за прошедшие годы и взяв его за стандарт предложить производителям BIOS воплотить его в соответствующие коды. Ан нет, не делается и перспектива довольно неопределенная. Конечно нельзя не упомянуть об одном фрагменте BIOS появившимся примерно в 1993г., который действительно соответствует упомянутым требованиям. Это BIOS32 Directory Service предназначенная для конфигурации PCI устройств. PCI шина, имея принципиально 32-разрядную адресацию вероятно, просто вынудила производителей на добавление в BIOS функций выходящих за рамки традиционного 16-битного режима (впрочем в 16-битном варианте эти функции тоже сдублированы). Лед тронулся, наконец, в области графики. VESA расширения BIOS видеокарт начиная с версии 2.0 начали поддерживать некоторые 32-разрядные функции. Но на этом все и кончилось.

Почему?

На, более чем субъективный, взгляд автора, сделано (или скорее не сделано) это преднамеренно. Прежде всего, производитель, не враг самому себе. Круг задач решаемых с помощью компьютера особенно в бизнес-приложениях, за которые легче всего раскошеливается потребитель, за прошедшие годы принципиально не изменился. Та же обработка текстов, электронные таблицы, базы данных. Возможности, а следовательно и сложность, софта за эти годы выросли, конечно, очень сильно, но производительность компьютеров совершила еще больший скачок. Производитель же больше всего заинтересован в том, чтобы заставить потребителя постоянно обновлять имеющуюся у него технику. Вот тут ему на помощь и приходит наиболее затратная с точки зрения ресурсов ОС Windows пожирающая их как виртуальная свинья и прожорливость ее каждой новой версии растет в геометрической прогрессии. Правда, многозадачность в данном случае, не главный потребитель ресурсов. В большей степени это следствие получившего широкое распространение подхода - упростить и ускорить работу программиста пусть даже в ущерб эффективности генерируемых кодов, а за производительность пусть отдувается процессор, даром что у него сотни мегагерц. Объектно-ориентированное программирование, Visual компиляторы как раз и ориентированы на такой подход и это во многих случаях, несомненно, оправдано поскольку очень облегчает создание программ со сложной структурой, ускоряет и упрощает создание графических оболочек программ, на что раньше уходило в несколько раз больше времени, чем на написание собственно самой программы. Тем более обеспечить в конкурентной борьбе быстрый выход новых программных продуктов на рынок, без подобных подходов, просто невозможно. Однако в случае с продуктами Microsoft это приняло какие-то гипертрофированные формы и на их, зачастую совершенно необъяснимую, медлительность жалуются владельцы даже очень неслабых компьютеров и... бегут покупать новые, еще более дорогие и мощные.

Очень нехорошая сторона этой медали еще и в том, что ОС Windows заняла то место которое должен был занимать BIOS т.е. стала фактически стандартом 32-разрядного взаимодействия пользовательской программы и периферии привязав возможность такого взаимодействия к конкретной ОС и альтернативы можно считать нет. UNIX подобные системы сконцентрировались в основном на сетевых технологиях, а их драйвера редко встретишь у купленного устройства, да и массовых программных продуктов на этих платформах мало. Эти системы довольно сложны в установке и администрировании т.к. исходно предполагалось их использование высококвалифицированными специалистами и у рядового пользователя сунувшегося в них, как правило, желание быстро пропадает. Только последнее время предпринимаются попытки сделать их более дружественными. К тому же, вследствие все той же многозадачности они будут так же неудачны для решения некоторых задач, как и Windows.

Возможно и другое соображение.

Высокопроизводительные компьютеры по своей сущности обеспечивают развитие высоких технологий и не только. Моделирование в механике, физике, химии - то, на что раньше требовались суперкомпьютеры производимые штучно и поставки которых в другие страны легко контролировались, теперь возможно на компьютерах доступных рядовому пользователю и выпускаемых миллионами, да и в немалой степени в странах третьего мира, что практически исключает возможность отслеживания - куда они попадают. Известный пример, когда группа программистов решила проверить возможность взлома шифров с 64 битным ключом, используемых банками при переводе денег, методом простого перебора возможных комбинаций. Создав для этого довольно эффективную программу, они разбили все множество перебираемых комбинаций на несколько сот фрагментов, и запустили ее на таком же количестве обычных компьютеров. Создав таким образом, раскиданный на несколько европейских стран параллельный компьютер они за довольно короткий (неделю) срок получили правильный ответ, перебрав астрономическое количество комбинаций, что раньше было возможно лишь на созданном специально для этих целей суперкомпьютере Агентства Национальной Безопасности США. Впрочем, эксперимент этот проводился с ведома фирмы - производителя программного обеспечения для банков, и криминальных последствий не имел, фирме же пришлось резко увеличивать защищенность своих шифров. Так вот, высокоразвитые страны производящие подобную технику, конечно заинтересованы в том, чтобы ее продавалось по всему миру как можно больше, но в то же время, желательно чтобы она не слишком технологически продвигала страны находящиеся на более низком уровне развития. Лучший способ добиться этого - сделать систему как можно более затратной и закрытой, что и происходит. Подобное соображение, казалось бы, будучи достаточно очевидным, работать не должно. Затраты на анализ слабых мест, поиск информации и создание своего альтернативного программного обеспечения, незначителен, даже в масштабах крупного (но твердо стоящего на ногах, а не едва сводящего концы с концами) предприятия, не говоря уж о масштабах государства. Насчет остального мира ничего не могу сказать, а вот по странам СНГ работает, и еще как, и причины вот в чем. Ученые, конструкторы или же руководители каких-либо структур определяющие, что и как приобретать, несомненно, прекрасные специалисты в своей области, но как правило плохо разбираются в компьютерной специфике, а зачастую вообще имеют о них весьма смутное представление, и оказываясь перед фактом, что уже имеющийся у них компьютер с задачей не справляется приходят к единственному остающемуся для них выводу - нужен гораздо более дорогой и мощный. В советские времена связующую функцию между заказчиками и поставщиками подобной техники выполняло государство с помощью громоздкой, неуклюжей системы всевозможных НИИ занимавшихся как раз вопросами: как определить кому и что нужно. И пусть там подавляющее большинство были дармоеды и пустозвоны, но были и действительно профессионалы и толковый руководитель мог при желании получить грамотную консультацию или даже пробить необходимую ему разработку. Сейчас все брошены выживать в одиночку, а роль государства вообще опустилась ниже нулевой отметки.

Иногда становиться обидно за какого-либо ученого вынужденного отдавать результаты своих исследований, фирмам из более богатых стран за поставку ему взамен нескольких "суперсовременных" моделей компьютерной техники, которая к тому же через полгода становиться вчерашним днем. Так и хочется крикнуть ему:
- Да не нужны они тебе!!!
Рядовой компьютер за несколько сотен долларов с запасом справиться с твоими задачами и не нужно выкидывать тысячи за "последний писк моды". Да! Программировать будет труднее, времени уйдет больше, так ведь сохранишь средства, на которые у нас несколько лет жить можно. Ситуация с государственными структурами еще более фатальна. Единственным критерием при приобретении какой-либо техники является: - кто будет посредником и сколько с этого можно поиметь. Естественно, комиссионных больше там, где техника дороже, дальнейшая же ее судьба впоследствии совершенно никого не интересует. Даже если этот принцип в некоторых случаях не работает, в дело вступает другой. Психология большинства руководителей традиционна - старайся выбить как можно больше, а там применение найдется. Но за все надо платить и, к сожалению зачастую вовсе не тем, кто тратит

Конечно, уход от многозадачной ОС к однозадачной вовсе не панацея от всех проблем, и во многих случаях не даст сколь-либо существенного результата, а попытка ухода в ассемблер и оптимизация кода лишь осложнит жизнь программистам, так же, несомненно, существуют задачи где действительно необходимы компьютеры с астрономической производительностью и такой же стоимостью. Существуют к тому же ОС типа UNIX, причем даже с открытой архитектурой как Linux и FreeBSD эффективность которых, несомненно гораздо выше чем Windows и во многих случаях вполне достаточен и оправдан переход на них. Но цель статьи - призыв к анализу каждой конкретной ситуации, особенно для задач по сложности - несколько выше средней, а так же попытка показать, на примерах, как этот анализ проводить. И, скорее всего призыв этот относиться конкретно к ограниченным в средствах всевозможным структурам и отдельным пользователям обремененным необходимостью решать задачи - требования которых превышают их финансовые возможности. (А вы видели передачу про Питерского умельца, который у себя на загородной даче, на установке, по сложности, напоминающей самогонный аппарат с ручкой, навертел редчайшего изотопа осмия стоимостью 200 000 $ за грамм на несколько миллионов долларов, а когда его повязали - оправдывался
- А у меня дешево и... много!?
Этот сюжет, правда немного переврав, даже сунули в известный криминальный сериал).

У достаточно продвинутого в этом вопросе читателя, несомненно, давно вертится на языке вопрос - а как же DOS Extender-ы, уж они то уж точно однозадачны. Вот ведь то самое к чему клонил автор все свои разглагольствования. Да, действительно, давно уже существуют для обычного 16-разрядного DOS-a расширители его до 32-разрядного режима. Это небольшие программы, либо пристегиваемые компоновщиком к телу основной задачи, либо запускаемые до нее. Их цель включить 32-разрядный защищенный режим и создать необходимую ему операционную среду. Естественно им будет уделено самое пристальное внимание, но сразу надо оговориться - программа на их основе не может быть полноценно 32-битной, ее тащит в прошлое 16-разрядный BIOS, как чугунный шарик прикованный к ноге карикатурного арестанта - чтоб не слишком прытким был. Но, кажется, будет уместным совершить для начала небольшое ознакомление с пресловутым защищенным режимом из-за которого весь сыр-бор

Что же представляет из себя защищенный режим. Ну, то что смещение (а это и есть тот самый живой или логический адрес с которым и приходиться работать программисту) стало 32 битным - это ежу понятно. Хуже обстоит дело с сегментами (это регистры CS:,DS:,SS:,ES:,FS:,GS: которые в любом режиме остаются 16 битными ), они теперь сами адрес не формируют, а поменяв название превратились в селекторы сегментов и адресуют 64 битные элементы в так называемой Дескрипторной таблице и которые так и называются Дескрипторы сегментов. Дескриптор задает начальную позицию в 4Г физической памяти, размер сегмента с шагом 4К, тип сегмента (код, данные, стек), присутствие и т.п., кроме разумеется того, что нужно (по мнению автора). Логический адрес суммируется с базовым адресом начала сегмента и получается физический адрес который и выдается на шину процессора. Дескрипторные таблицы бывают - одна глобальная (обычно для операционной системы) и много локальных (по одной для каждой задачи). Однако мучения процессора в формировании адреса во всех многозадачных операционных системах на этом не заканчиваются. Между логическим и физическим адресами влезает страничное преобразование которое формирует промежуточный так называемый линейный адрес. На кой чорт оно нужно? Именно оно порождает пресловутые разделяемые библиотеки DLL в Windows.

Вся доступная физическая память делится на куски по 4К, которые с помощью хранящейся в памяти таблицы страниц (очень похожей на Дескрипторную таблицу) могут отображаться на разные логические адреса. В физической памяти располагается ОДНА разделяемая библиотека, которая отображается в логические адреса разных задач и каждая задача считает ее своей персональной библиотекой. На этом экономится память кодов, но это еще не все. Страницы можно отобразить на несуществующую память расположив ее например на Hard диске. В случае обращения к такой, так называемой неприсутствующей странице возникает прерывание и операционная система переносит ее с Hard-а в оперативную память, а те страницы к которым, по мнению системы, нет обращений она выкидывает на Hard освобождая память. Это и есть Виртуальная память, а файл неиспользуемых страниц - Swap-файл или файл подкачки. Переход через 4К границу адреса обязательно вызывает загрузку новой страницы. Чтобы это не сильно влияло на быстродействие, у процессоров создан для страниц небольшой специальный кэш, не имеющий ничего общего с кэш памятью кодов и данных.

Несмотря на то, что у автора к страничному преобразованию оч-чень нехорошее отношение, надо сказать про него и что-то хорошее. Для задач где требуется динамическое выделение памяти, страничное преобразование позволяет легко и быстро ее использовать, причем на все 100%. К примеру - задача. Из массива слов надо сделать два. В один выписать слова начинающиеся на большую букву, во второй - на маленькую, причем для неких дальнейших действий желательно чтобы все три(входной и два выходных) массива находились в памяти одновременно. Дело в том, что выделяя этим двум выходным массивам свободную память, заранее неизвестно, какой будет большим, а какой маленьким. Поделить ее пополам - а вдруг большему не хватит, а у меньшего дуром пропадать будет. В системах без страничного преобразования всевозможные алгоритмы перетасовки динамической памяти, иначе как извращенческими не назовешь. Со страничным преобразованием это элементарно - выделяй большему массиву страницы, по мере необходимости, из числа свободных и все. У компиляторов даже тип данных под это появился - Stream. (Вообще-то, практика показывает, что задачи критичные к динамическому управлению памятью, или наоборот к страничному преобразованию, бывают крайне редко, а в большинстве случаев находятся альтернативные, причем не менее эффективные подходы. С упомянутой выше задачей, можно вывернуться, к примеру, так: направим массивы навстречу друг другу, один будет начинаться в начале свободной памяти, а другой в конце. Конечно заполнять массив "задом наперед" не слишком удобно, да и нужно контроллировать их встречу. В точке "рандеву" память кончится. Однако, для трех и более выходных массивов этот номер не пройдет).

Основной "потребитель" динамического управления памятью, именно многозадачность. ОС должна эффективно выделять память новым задачам, и не оставлять в памяти "дыр" от старых.

Почему же автор так не любит режим страничного преобразования адреса. Дело в том, что существует некий круг задач интенсивных рассчетов и моделирования, где динамических массивов не требуется, а само страничное преобразование может очень сильно понизить производительность. Это задачи обработки больших массивов (десятки и сотни мегабайт) данных, с непоследовательным доступом к элементам.

Приведу пример: кэш страниц Pentium Pro - 512 страниц (а у бедного AMD K6-2 только 64). При размере страницы 4К это 2М памяти (начиная с Pentium, добавлены страницы по 4M, но операционные системы используют их как правило, только для адресации видеопамяти). Записываем в память двумерный байтный массив с размером строки больше 4К и числом столбцов больше 512 (общий размер больше 2М). Причем записываем по строкам. Адреса в памяти в этом случае следуют подряд, и подкачка новой страницы происходит 1 раз за 4096 операций записи. Потерь времени можно считать не происходит. Но прочтем этот массив по столбцам. Каждая операция чтения - обращение к новой странице т.к. строка больше 4К, кэш страниц не работает т.к. строк больше 512 и он переполнен. Следовательно, соответствующий элемент таблицы страниц должен подгружаться из памяти при чтении КАЖДОГО байта, а это очень долго. Самое удивительное - что в этом примере кэш память первого уровня - ПОНИЖАЕТ быстродействие (со страничным преобразованием это уже не связано). Судите сами. Массив больше кэша - кэш переполнен (кэш первого уровня размером 16К содержит 512 строк по 32 байта). При обращение к каждому последующему БАЙТУ массива в кэше не оказывается достоверной строки, что вызывает заполнение всей строки т.е. 4 цикла чтения вместо необходимого одного. При определенных размерах массива эта же участь постигнет и кэш второго уровня. Правда, элементы таблицы страниц позволяют вам запретить кэш память, но ни одна операционная система не дает вам доступа к этой таблице. Лучшим выходом было бы запрещение кэш памяти на уровне дескрипторов (загружаете такой дескриптор в малоиспользуемый сегментный регистр FS: или GS: и через него обращаетесь к памяти), но INTEL не предоставила такую возможность дескрипторам, несмотря на имеющиеся в них практически не используемые биты, за что автор и катит на нее бочку. (Впрочем, ой-ли не предусмотрела. Оставить без внимания столь явную дыру в работе с большими массивами, высококлассные разработчики вряд ли могли. Другое дело - афишировать это совсем не обязательно. Достаточно изменения состояния каких-либо, известных лишь узкому кругу разработчиков специализированного ПО, бит в регистрах управления и биты дескриптора начинают вести себя совершенно по другому. С электронной точки зрения затраты вообще смехотворны - механизм блокирования кэш памяти уже существует для страниц, добавить несколько логических элементов да пару-тройку связей и вся забота, но это все авторские измышления). Конечно, кэш память можно вообще всю отключить с помощью предназначенных для этого битов в регистре управления, но всю то, как раз отключать и нельзя - перестанет работать кэш команд, а потери на их выборку многократно превзойдут выигрыш от операций с данными. Динамически включать и выключать кэш в зависимости от исполняемых фрагментов - теоретически возможно, но практически малоприменимо и скорее может рассматриваться из области курьезов.

Автор был удивлен узнав, что вышеприведенные соображения послужили темой для всевозможных диссертаций еще в эпоху IBM360/370 и содранных с них ЕС ЭВМ. Прообразом современных многозадачных ОС тогда стала Система Виртуальных Машин (СВМ) - кстати сперва не подержанная самой IBM. Управление памятью базировалось так же на страничном принципе. Уже тогда проводили анализ - как это отразится на обработке матриц (автор больше привык к слову массив). Да, еще нужно упомянуть о различиях между видами кэш памяти: со Сквозной (Write Thru) и Обратной записью (Write Back). Первая производит запись одновременно и в кэш и в память из-за чего процессору приходиться ждать пока закончиться довольно медленный цикл памяти. Вторая старается писать только в кэш и в память сбрасывает данные только при его переполнении. Общепринятое мнение что Обратная запись быстрее Сквозной и, следовательно, лучше верно только в случае, когда данные помещаются в кэш, если же нет то быстрее становиться как раз Сквозная. Судите сами: при переполненном Обратном кэше из него сначала нужно списать содержимое в основную память и только потом процессор получает разрешение на запись в кэш - двойная операция. Можно даже сказать, что для Сквозной - на операциях записи, кэширование запрещено. К сожалению, на последних моделях компьютеров практически исчезла возможность задания с помощью Setup типа кэш памяти Второго уровня. Кэш первого уровня у всех процессоров расположен на кристалле, у процессоров пятого и последующих поколений он Обратный. Кэш первого уровня отличается (для программиста) от всех последующих, своей разрядностью. Она у него в 4 раза больше разрядности внешней шины данных процессора (которая для 486 - 32, а для последующих 64 разряда), а для кэш второго и возможно последующих уровней они равны. Поэтому все операции с внешней памятью у процессоров занимают 4 цикла - пока не заполнится строка кэш и называются потоковыми (Burst), кроме случаев, когда кэш удается запретить. Это определяет принципы оптимизации для операций с памятью. Внутри интенсивных циклов, желательно чтобы память данных задействовалась кусками равными разрядности кэш, и адреса этих кусков были бы в памяти выровнены. Правда, это не всегда возможно, а иногда сильно запутывает программу. Например, в цикле задействуются из 4-х разных массивов 4-байтные элементы, по одному и тому же индексу (ни в один кэш массивы не лезут). Если расположить массивы не подряд,
[A0..AN], [B0..BN], [C0..CN], [D0..DN]
а создать один счетверенный
[A0,B0,C0,D0]..[AN,BN,CN,DN]
то разница в быстродействии составит 4 раза (разница в быстродействии всей программы поменяется в зависимости от процентного соотношения времени на операции с памятью содержащей эти массивы к общему времени и может быть небольшой). Второй из основных принципов повышения быстродействия с учетом особенностей кэш - выравнивание адресов тех точек, куда совершаются переходы. Выравнивать естественно следует только те адреса, куда переходы идут часто. Правда, схемы предсказания переходов могут уменьшать влияние невыровненых адресов, однако, вреда от выравнивания не бывает, разве что коды становятся длинее и в результате короткие переходы могут не доставать до адресата. Надо заметить, что при больших объемах оперативной памяти, на многих моделях материнских плат на втором уровне кешируется не вся память, а какая-то ее часть (64-128М). Процессоры же кешируют всю доступную память. С другой стороны во всех современных чипсетах используют глубокие FIFO буферы между процессором и памятью, которые уменьшают требования к оптимизации кода для операций с памятью и в некоторых случаях стирают разницу в быстродействии между Сквозной и Обратной видами кэш памяти.

Следующая мерзопакостная вещь, порожденная многозадачностью - уровни привилегий. Их у процессора 4. Единственный приличный 0 (Высший) - выполняются любые команды процессора. Во всех многозадачных операционных системах и у известных автору Dos Extender-ов, пользователю присваивается самый низший уровень привилегий 3. С уровнем привилегий также связано выполнение операций ввода-вывода и разрешения-запрещения прерываний, правда здесь этот уровень можно менять программно, но только операционной системе. Естественно, что эти операции для пользователя запрещены. Попробуйте в Windows считать или записать что-то в порт - система тут же вас выплюнет с диагнозом Нарушение общей защиты - только через драйвер, у которого уровень привилегий выше. А обращение к драйверу, это переключение задачи, это прохождение шлюзов (а вдруг это вирус или злодей пытается пролезть на более высокий уровень привилегий).

Тут страдают те, кто подключает к компьютеру всевозможные нестандартные, а зачастую и изготовленные собственными силами устройства для управления, измерений или сбора данных. Даже некоторые иностранные фирмы изготовляющие нестандартное оборудование, до сих пор вынуждены комплектовать его программами только под DOS, который способен работать с портами ввода/вывода напрямую. Писать драйвера защищенного режима под Windows - нужна оригинальная документация Microsoft, а это удовольствие не из дешевых да и не всякому программисту это под силу. Но если ваши данные превышают 64К то DOS вам не помощник, а обрабатывать их такими кусками на 32-разрядной машине имеющей десятки мегабайт памяти - это уже извращение, да и скорость работы через драйвер не всегда может устроить. Между прочим, из-за этого ограничения вынуждены были сделать исключение для видеоадаптеров. Сейчас в них отображают порты ввода/вывода на обычную память и обращение к ним идет без замедляющих ограничений. Но остальным-то, что делать?

Может возникнуть вопрос. Если какая-то важная задача в свете выше сказанного будет создана под однозадачную среду, то лишившись механизмов защиты она станет ненадежной?
- Ничуть.
Механизмы защиты по своей сущности защищают многозадачную ОС от вашей задачи и различные задачи друг от друга. В случае ошибки, ваша задача все равно погибнет как бы важна для вас она не была независимо от того в защищенной многозадачной среде она работала или нет. И какая вам разница - уцелела после этого ОС или нет. Нажать RESET в крайнем случае, не так уж трудно. Но кстати, часть механизмов защиты успешно срабатывает и в однозадачной среде, спасая разумеется ОС, но не задачу.

Что-же имеется на сегодняшний день из вполне доступных DOS Extender-ов и ориентированных на них языков программирования. В свете последней редакции этой статьи, на первое место явно выходит не так давно появившийся многообещающий TMT Pascal. Работающий с несколькими Dos Extender-ами, из которых наиболее прогрессивный PMODE/W (поставляемый только в коммерческом варианте, каковой так же включает отладчик, онлайновый Help и еще некоторые компоненты). Имеет встроенный ассемблер поддерживающий команды новых процессоров, но не включающий, ненужные в данном случае, системные команды. При работе в Dos уровень привилегий задачи высший, операции ввода-вывода разрешены. Единственный огорчительный недостаток - страничная организация памяти. С ее помощью они объединяют в единое целое области памяти выше и ниже первого мегабайта. Из-за небольшой таблицы страниц, у некоммерческой версии ограничение на размер задачи 1.5M. Впрочем, коммерческая версия ограничений не имеет, и есть предположение, что у PMODE/W наконец задействованы страницы по 4M для области данных, что практически снимает недостатки страничного преобразования. По своей сущности TMT Pascal практически повторяет Turbo Pascal для Dos, но в 32-битном режиме. Бесплатную, ограниченную версию можно скачать со странички http://www.tmt.com, где так же можно приобрести и коммерческую версию. Довольно умеренная цена 39$ делает ее вполне доступной для тех, кто не страдает от излишка денег, однако, требуется кредитная карточка для возможности оплаты. Следом идет DOS4GW фирмы Rational, используемый как основной знаменитым компилятором Watcom C++ с которым сталкивались многие любители компьютерных игр вроде DOOM2. Это уже довольно старый и громоздкий Dos Extender. Надо заметить, что TMT Pascal его тоже поддерживает. Менее распространены - компилятор NDP C++ и Ассемблер РharLap со своими DOS Extender-ами. PharLap в частности использовала известная программа для разработки печатных плат - P-CAD. Прежде всего, DOS Extender-ы не взаимозаменяемы и программа откомпилированная под один не будет работать с другим, да и отлаживать ее можно только специально созданными под каждый из них отладчиками. Все старые DOS Extender-ы как и Windows присваивают пользователю самый низкий уровень привилегий - 3, но с существенной разницей - операции ввода/вывода и управления прерываниями в них разрешены. Страничное преобразование используют все, но только у PharLap его можно запретить. В свое время от более тесной работы с ним, автора оттолкнул только отладчик PharLap, чересчур напоминающий DOS-овский DEBUG, при одном воспоминании о котором, мороз продирает по коже. Б-ррр...

Низший уровень привилегий и страничное преобразование очевидно установлены в этих Dos Extender-ах для совместимости с Windows, другого объяснения автор найти не смог. Самое слабое место DOS Extender-ов - драйвера. Можно считать, что их нет. В первую очередь это дисковые операции т.н. 13h Interrupt (Int 13h). Да и устаревший Himem.sys определяющий для DOS, сколько у него верхней (Extended) памяти - больше 64M вообще не видит. Int 13h обеспечивает основную работу с дисками и из-за 16-разрядного адреса может передавать данные только в пределах первого мегабайта памяти, к тому же порциями менее 64K. Для обмена дисков с памятью выше первого мегабайта требуются повторные передачи. Малые порции данных приводят к многократным вызовам Int 13h , при этом кроме инициализации устройств и ожидания от них готовности, при использовании DMA передач каждый раз требуется полная очистка кэша, к тому же, существующее ограничение для Int 13h на количество цилиндров для Hard дисков - не более 1024 давно ограничило размер дисков до 528M. Введеный как стандарт режим LBA пересчитывает соотношение головок, секторов и цилиндров, с целью уменьшения последних, но на 8.4G дисковой памяти и его возможности заканчиваются, а ведь уже на подходе более 20G. Непосредственно IDE стандарт позволяет адресовать 64K цилиндров, 16 головок и 255 секторов, что дает 136,9G на каждый накопитель, которых вроде должно хватить на обозримое будущее, причем в регистре головок остаются еще два неиспользуемых бита позволяющих со временем учетверить и эту цифру. Производитель BIOS фирма Phoenix еще в 1995г. разработала дополнение к Int 13h, решающее проблему адресации дисков более 8.4G. Это расширение именуется EDD 1.1 и с последующими добавлениями 3.0. Возможно после слияния Phoenix и Award этот стандарт станет общим. Однако главная проблема не решена. Даже новый вариант остался все равно 16-битным со всеми присущими недостатками. Получить же от новой объединенной фирмы вразумительный ответ по поводу работы с дисковыми операциями в 32-битном режиме, автору не удалось. На задаваемые по E-mail вопросы у них отвечает контекстный автоответчик, который на основе встречающихся в вопросе фраз и слов выдает несколько стандартных ответов из группы FAQ. Естественно, все выбранные роботом ответы не имели ни малейшего отношения к сути вопроса. На момент апрель/май 2000г. автор все же закончил полновесный 32-битный драйвер Hard дисков, работающий в режиме PCI IDE Bus Master, и использующий всевозможные UDMA, если они поддерживаются чипсетом и диском. Правда файловая система Dos его поддерживать не способна и работать приходится на уровне физического доступа к диску (организован так же логический уровень для работы в пределах выбраного раздела). Сравнение с обычными, даже Dos Extender-ными программами, дает впечатляющие результаты. Поиск некоего контекста по всему диску у 32-битной версии известной программы DiskEditor идет примерно со скоростью 1G/час, на 350Мгц процессоре и UDMA33 10G Hard диске. Там же, программа с пресловутым драйвером управилась с тем же 10G(всем!) диском - за 15 минут, причем имея исходные тексты, контекст поиска можно было делать составным, и вообще сколь угодно сложным. Текст драйвера можно найти там же где и эту статью - на страничке автора.

Видеосистема, как упоминалось выше, наконец начала уходить в полноценную 32-битность, не привязанную к конкретной ОС, что вообще-то необходимо было сделать сразу с появлением PCI шины. BIOS видеокарт начали расширять VESA стандарты, поначалу ограничивающиеся только добавлением новых видеорежимов. Но, начиная с версии 2.0 стало, наконец, возможным включить всю видеопамять карты в общее адресное пространство одним нефрагментированным куском. Это режим т.н. LFB (Linear/Flat Frame Buffer). До его появления, если у вас не было драйверов под вашу систему, приходилось упихивать мегабайты видеопамяти в 128К отведенные на эти цели более 20 лет назад (тогда это выглядело более чем роскошно, а уж про то чтоб занять ее всю, казалось бы и речи быть не может. Кто этого не помнит - цветной адаптер поддерживал в графике целых 4! цвета, а монохромный всего два). Добавились функции дублирующие основные, но выполненные целиком в 32-битных кодах. Есть ссылки и на то, что наконец станет доступной акселерация. Аппаратно реализуемые функции подобные BitBLT, LineDraw они и в Африке хороши, а не только в Windows. Появился стандарт VBE/AF - Accelerator Functions specification, который можно найти на страничке:
http://www.talula.demon.co.uk/allegro//
однако, производители его поддерживать не торопятся, а попытки создать драйвера самостоятельно натыкаются на закрытость информации по описаниям аппаратных регистров видеокарт обеспечивающих акселерацию. Более подробно о работе с функциями VESA можно прочитать в статьях С.А. Андрианова в журнале "Мир ПК" номера 7 и 8 за 1998г, которые имеются в Интернет на http://www.osp.ru/pcworld . Приме...

_________________
:dj: https://mastodon.social/@Shaos


23 Apr 2007 06:11
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
Судя по всему статья ОЧЕНЬ старая - с тех пор и PMODE/W стал бесплатно входить в OpenWatcom, и свободные реализации биосов появились. Создаётся ощущение, что автор делает неправильные выводы, ища корень зла Windows в многозадачности - искать надо в кривизне ОС как таковой ;)
Видимо он не работал толком с Linux, а также знать не знает про RealTime ОСы...

_________________
:dj: https://mastodon.social/@Shaos


23 Apr 2007 06:35
Profile WWW
God
User avatar

Joined: 29 Dec 2003 01:00
Posts: 1101
Location: Москва
Reply with quote
Post 
Shaos wrote:
Судя по всему статья ОЧЕНЬ старая - с тех пор и PMODE/W стал бесплатно входить в OpenWatcom, и свободные реализации биосов появились. Создаётся ощущение, что автор делает неправильные выводы, ища корень зла Windows в многозадачности - искать надо в кривизне ОС как таковой ;)
Видимо он не работал толком с Linux, а также знать не знает про RealTime ОСы...

ПО моему автор просто разделяет вещи, есть пользовательская ОСЬ а есть ОСЬ для управления оборудованием. ВОт для этого уже родились вполне дееспособны ОС.
А вот про BIOS в точку, устарел он за 15 лет то. Пора бы и обновить!


23 Apr 2007 10:49
Profile ICQ WWW
Retired

Joined: 03 Aug 2003 22:37
Posts: 1474
Location: Moscow
Reply with quote
Post 
CHRV wrote:
ПО моему автор просто разделяет вещи, есть пользовательская ОСЬ а есть ОСЬ для управления оборудованием. Вот для этого уже родились вполне дееспособные ОС.
А вот про BIOS в точку, устарел он за 15 лет то. Пора бы и обновить!

Полностью согласен!

_________________
Extreme Entertainment


23 Apr 2007 12:02
Profile
Banned

Joined: 12 Oct 2006 16:44
Posts: 608
Reply with quote
Post 
Автор статьи безответен - по е-mail не отвечает


23 Apr 2007 18:07
Profile
God
User avatar

Joined: 29 Dec 2003 01:00
Posts: 1101
Location: Москва
Reply with quote
Post 
А у меня есть лицензионная http://phystechsoft.ru/ptsdos/

Кстати при современных обьемах стартап ПЗУ материнок в комплект к бивису можно разместить батхэд - небольшую ось, ну например тот же ptsdos.
Наеврно уже так делают...


24 Apr 2007 02:07
Profile ICQ WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
CHRV wrote:
А у меня есть лицензионная http://phystechsoft.ru/ptsdos/

Кстати при современных обьемах стартап ПЗУ материнок в комплект к бивису можно разместить батхэд - небольшую ось, ну например тот же ptsdos.
Наеврно уже так делают...


C линуксом так делают вроде - минимальный биос, нужный только для работы линукса, ну и сам линукс в минимальной конфигурации в той же ПЗУ

_________________
:dj: https://mastodon.social/@Shaos


24 Apr 2007 06:28
Profile WWW
Banned
User avatar

Joined: 20 Mar 2005 13:41
Posts: 2141
Location: От туда
Reply with quote
Post 
CHRV wrote:
А у меня есть лицензионная http://phystechsoft.ru/ptsdos/

У меня тоже. :kruto:
CHRV wrote:
Кстати при современных обьемах стартап ПЗУ материнок в комплект к бивису можно разместить батхэд - небольшую ось, ну например тот же ptsdos.
Наеврно уже так делают...

Слышал, тока PXE загрузчик и ROMDOS. Но все же, объемы не так уж и велики... Даже сам БИОС пожат.
И вообще, не согласен я с автором по поводу многозадачности. Очень часто у меня крутятся несколько задач. Понятно, что активна одна, но остальные в фоне тоже работают а не простаивают. К примеру, даже если я пишу ДВД, у меня играет музыка и/или я шарусь в тырнете. Ясно, что резак не простаивает, ожидая моего внимания... К тому же, важность задач я планирую сам: если мне надо покодить фильму, то я стараюсь ничего больше не запускать, но если мне вдруг что-то нужно, я уменьшаю приоритет кодеру и завожу прогу, нужную мне. Урезая ресурсы одной задаче и выделяя другой я настраиваю комп так как нужно мне. К тому же, по поводу привелегий, я юзаю маленький унверсальный драйвер UserPort, который позволяет мне достучаться до портов напрямую, даже в 32х битах (оформляем простой StdCall). Кстати, 95/98 как раз таки порты и не защищала, а позволяла писать прогам туда все что угодно. ИМХО это ее и делало нестабильной (прикинь, я остановлю DMA.... :o ). Видимо, автору это было не известно в далеких 9х...


24 Apr 2007 06:34
Profile
Retired

Joined: 03 Aug 2003 22:37
Posts: 1474
Location: Moscow
Reply with quote
Post 
CHRV wrote:
А у меня есть лицензионная http://phystechsoft.ru/ptsdos/

Поддержим отечественного производителя спутников серии "Ураган"! ;)

_________________
Extreme Entertainment


24 Apr 2007 11:52
Profile
Senior

Joined: 09 Jun 2005 05:34
Posts: 112
Reply with quote
Post 
CHRV wrote:
Кстати при современных обьемах стартап ПЗУ материнок в комплект к бивису можно разместить батхэд - небольшую ось, ну например тот же ptsdos.
Наеврно уже так делают...


Есть новый стандарт, называется EFI. Extensible Firmware Interface. По сути это - микро-ОС, размещенная в ПЗУ. Поддерживает работу с USB, различными носителями, читает файловые системы, грузит файлы. Массово применяется на данный момент только в интелмаках, возможно еще в IA-64 машинах (хотя я не видел их живьем).


24 Apr 2007 23:12
Profile
Fanat

Joined: 30 Jul 2007 10:31
Posts: 51
Reply with quote
Действительно, автор не отвечает на письма, но некоторые страницы его сайта имеются на archive.org. Т.к. они довольно интересные считаю своим долгом выложить их здесь.

Quote:
Проект 32-битной однозадачной ОС

Прежде всего, данный проект не ставит целью создать конкурента ОС Windows всех видов. Его цель заполнить пустующую нишу DOS подобной однозадачной ОС, но полностью 32 - битной. Одна из причин необходимости такой ОС - желательность для некоего класса задач, запрета страничного преобразования, простоты операций ввода/вывода, экономного расхода памяти самой ОС и выделения всего процессорного времени одной задаче. Подробнее все это расписано на этой же страничке в статье "Отрицательные стороны многозадачности ОС". В большей степени это относится к задачам интенсивных рассчетов, моделирования, управления внешними устройствами сбора и обработки информации. По назначению, это будет скорее инструментальная ОС, т.е. ближе к QNX, но без ее многозадачности, с интерфейсом традиционного ДОС и встроеной оболочкой типа NC/VC.

Ну нельзя же, до сих пор, при необходимости сделать свою простую програмку, делать это в антикварном 16-битном ДОС и упихивать все в несчастные 640К, да еще порциями не более 64К (а поработайте-ка с портами ввода/вывода из под Windows...).

Есть предположение, что не только те, кто решает задачи требующие подобную среду, но и обычные владельцы компьютеров, для многих применений вполне удовольствовались бы однозадачной средой, если под нее существовали бы устраивающие их прикладные программы. Непомерная прожорливость и медлительность Windows и значительная сложность Linux (даже несмотря на попытки сделать ее более дружественной), говорят в пользу подобной точки зрения, Да и то, что DOS+NC гораздо проще Windows и уж тем более Linux может создать определенное предпочтение. Кстати задача работающая с несколькими однотипными окнами отнюдь не требует многозадачную среду (чтоб каждое окно было отдельной задачей), ей лишь желательны динамические структуры данных (см.ниже), чтобы управлять выделением памяти для этих окон.

Вообще идеология данной ОС прямо противоположна общепринятым подходам "облегчить жизнь программисту, а за производительность пусть отдувается компьютер - даром что у него сотни мегагерц и мегабайт". Данная ОС "удобна" именно компьютеру, зато позволяет задействовать его ресурсы по возможному максимуму (хотя есть частные исключения, например вряд ли удастся задействовать аппаратную акселерацию видеокарт, документация по которой практически недоступна, а следовательно невозможно создание драйверов).

Внимание! Проект этот частный, никем не финансируемый, не сулящий никаких коммерческих перспектив и вообще непонятно почему начавший реализовываться. Вероятно, причины побудившие автора к его реализации те же, что побудили вольноопределяющегося Марека стать редактором журнала "Мир животных"...

Оболочку предполагается сделать подобной Norton/Volkov Commander ибо по убеждению автора, более простой, оперативной и достаточно удобной оболочки для работы с файлами, человечество еще не придумало. Встраивание оболочки в ядро системы имеет недостаток - другую более подходящую по своему вкусу оболочку не поставишь (например попытка Microsoft, в свое время, создать альтернативу NC - свой Dos Shell провалилась, и автор не встречал никого, кто ей бы пользовался). Возможно это тоже решаемо. Система предполагается более/менее открытой и переписать при желании оболочку на лучшую - флаг в руки...

Почему - более/менее?

Ну это исходя из опыта создателей V2_OS. Полностью открытый, на стадии разработки, исходный текст привел к тому, что появилось множество измененых вариантов этой ОС, несовместимых друг с другом и неотслеживаемых авторами. Объеденить в единую все новоявленые версии, пусть даже с хорошими изменениями, занимает времени больше чем создание собственно ОС. Поэтому авторы V2_OS оставили тексты открытыми, но засунули их на своем сайте подальше, чтоб найти их было потруднее. Облегчило ли это им жизнь, автору неизвестно. Появление сторонних версий готовой ОС, это нормально при условии их полной совместимости с оригинальной, или приведение к совместимому варианту обеих. Но когда ОС на стадии разрабоки желательно изменения предлагать только в рамках авторской версии.

Голландская V2_OS практически преследует те же цели. Однако хорошего впечаления она пока не произвела, но это возможно из-за ее далеко незавершенности. Ну что ж. Попробуем сделать получше. Возможно на стадии готовности проекта проявятся преимущества и недостатки обеих систем. Создатели V2_OS нажимают больше на ее мультимедийное и игровое применение, а данная ОС больше инструментальная.

Исполняемые файлы скорее будут напоминать COM, чем к EXE. Предполагается совпадающая модель памяти для кодов и данных в пределах выделеного задаче логического сегмента (но не от 0 до 4G). Стеку выделяется отдельный сегмент не совпадающий с CS/DS. Заголовок вероятно так же будет отсуствовать и старт задачи происходить с логического 0. Reallocations заголовка EXE файлов не предполагаются вообще. Нужда в них возникает крайне редко и адрес в физической (или линейной) памяти можно будет получить альтернативными способами (для этого можно предусмотреть системную функцию). При необходимости, получить доступ ко всем 4G памяти можно будет через системные дескрипторы, правда только в этой однозадачной ОС. В случае ориентировки задачи и на многозадачную ОС это не пройдет, системные дескрипторы там должны быть недоступны. Работать прикладная задача будет с высшим уровнем привилегий. Нужды в защите "чужих" задач в однозадачке нет, а вызовы системных функций не будут требовать переключения задачи для смены уровня привилегий, что гораздо быстрее. Это выйдет "боком" в случае моногозадачки, где эта же задача на системных вызовах "утонет" в переключениях.

Название скорее всего останется OSKA т.е в уменьшительном русском произношении "маленькая операционная система". Какого-либо аббревиатурного содержания во второй половине названия нет. Наиболее логичное DOS32 вероятно закопирайчено вездесущим Microsoft для совершенно сторонней этим целям программы какого-то своего backup.

Разработка ведется на нескольких Ассемблерах из-под Dos.

Требование к процессору - минимально 586 семейства. Основная причина - использование переадресовки прерываний в V86 режиме. Для их задействования требуется Intel Pentium, AMD K5 и т.п. но их нет у Cyrix

В создание языков высокого уровня, предлагается всем желающим попробовать свои силы на этом поприще. Автор этим точно заниматься не будет, хотя если таковых не найдется, систему можно уже сейчас считать мертворожденной. Впрочем существует например FREE Pascal в исходных текстах. Могут найтись C и другие языки. Положим сделать сразу хороший оптимизирующий, а то и объектно-ориентированый компилятор чересчур непросто, но пусть для начала появится хоть какой, лишь бы ошибок делал поменьше. Писать уже можно будет. Кстати, исходники Watcom C говорят открыли.

Автор не сторонник объекто-ориентированого програмирования. Оно не слишком подходит для счетных задач. Это вообще очень затратный подход к программированию, чем кстати перегружены продукты Microsoft. Хотя для некритичных ко времени исполнения фрагментов, кому нравится - пусть использует.

Подход высокоуровневых компиляторов к работе с файлами так же, предполагается к реализации не совсем традиционный. Раньше ОС создавала небольшие файловые буферы, через которые и осуществлялся обмен мелкими порциями, причиной чему были, небольшой размер памяти и невозможность прямой адресации данных превышающих 64К. Сейчас предполагается обмен файла исключительно напрямую с буфером задачи, минуя буферизацию ОС. (напимер такие операции Pascal как readln / writeln должны идти через собственную буферизацию организуемую компилятором который скорее всего просто будет считывать весь файл в память, а затем изображать над ним работу по записям. Маловероятно что вам попадется текстовый файл способный не влезть в память даже недорогой машины). Пока, полностью, идеология работы с файлами не вырисовалась.

Кстати, работа со структурами данных предполагается более ориентированой на дескрипторы, когда любой структуре может быть выделен свой дескриптор. Логический адрес ее начинается с 0, а размер начинает контроллироваться пределом (правда с шагом 4К). Смысл это имеет только для структур значительного размера. Динамические структуры будут доступны только через свои дескрипторы. Это имеет и недостаток. Свободных селекторов всего два (GS, FS) и слишком часто тасовать дескрипторы плохо, ведь они подгружаются из памяти, а это не есть быстро.

Ситуация с системными утилитами, и минимально необходимым набором прикладных программ. По возможности, автор будет их делать сам, но помощь не помешает. В одиночку - не хватит никакого времени. А без них система тоже мертва. Впрочем, этим можно заниматься только после готовности системы хоть на минимальном уровне. На стадии проекта это не актуально.

То же можно сказать про драйвера не входящие в минимальный набор, и про поддержку сторонних файловых систем.

Вообще писать собственно ОС - самое неблагодарное занятие. Практика показывает - материально что либо поиметь вероятно только с прикладных программ, тем более у нас, где платить за программы считается признаком очень дурного воспитания, а то и вообще - законченого идиотизма. Да и Linux тенденции - ОС должна быть бесплатной, находят горячий отклик в сердцах потенциальных халявщиков. Однако, например хороший текстовый процессор (с масштабируемыми (своими, а не лицензионными TTF) шрифтами, вставкой таблиц, но без всеохватной раздутости Word) мог бы иметь определенный успех, при близкой к символической цене "левого" лазерного диска.

Файловая система предполагается своя, с преимущественно нефрагментированым хранением файлов. Кстати, ФС V2_OS предполагается подобной. Чисто нефрагментированное хранение файлов имела RT-11 для компьютеров PDP. Доступ к файлам подобная система обеспечивает более простой и быстрый, однако быстро расходуется нефрагментированная свободная память и требуется последующая дефрагментация. Может сложиться ситуация, когда при попытке сохранить результат работы, вы получите сообщение, что нет ни одного свободного фрагмента достаточной длины, хотя свободной фрагментированой памяти будет предостаточно. Неясно, что в этом случае сделают создатели V2_OS, но данная ФС предполагает сохранение в таком случае файла фрагментированым, по принципу - предыдущий фрагмент указывает на последующий (принцип известный давно, но кажется никогда не реализовывавшийся). Впоследствии можно провести дефрагментацию, т.к. работа с фрагментироваными файлами резко замедлится.

Вместо FAT использоваться будет его аналог Linear File Allocation Table (LFAT), который будет хранить информацию о свободных и занятых фрагментах, их стартовом адресе и размере.

Для большей устойчивости ФС предполагается в конце каждого файла (или его фрагмента) один сектор выделять на полный описатель файла, (включая его положение в дереве каталогов). Таким образом, даже при полном уничожении ФС, она будет практически полностью восстановима (опыт показывает что полностью данные на диске затираются редко, чаще всего страдают FAT или DIR). Это так же допускает возможность хранить LFAT в оперативной памяти, не переписывая ее на диск при записи каждого файла. Предполагается привлечь к хранению информации о незавершеной последней записи CMOS, и при сбое питания, при перезапуске система сможет из описателей файлов восстановить LFAT (что-то вроде автоматического запуска DiskScan, при незавершеном выключении Windows). Каждый записываемый описатель будет хранить ссылку на предыдущий, что при сбое питания позволит восстановить всю цепочку записаных файлов и скоректировать LFAT и DIR. LFAT предполагается размером 128К, таким же как и FAT16, что позволит без проблем кешировать и ФС FAT16. Размер в 128K позволит хранить в LFAT до 16К фрагментов, что в зависимости от распределения составит 8 - 16К файлов на раздел (а если хранить только размеры, то эта цифра удваивается). Предполагается что если у пользоваеля большой диск, то и часть файлов там тоже будут большими а для очень большого количества маленьких лучше сделать больше разделов. Хранение дерева каталогов пока вообще не определено, хотя текущий каталог (DIR) предполагается хранить в памяти, подобно LFAT, Собственно в памяти предполагается хранить два LFAT и два текущих DIR, по числу окон оболочки, что при переписи файлов позволит получить их полное кеширование. Работа задачи с большим числом разделов будет приводить к перезагрузке кешей. Вообще, для хард дисков, предполагается исключительно "щадящий" по сравнению с традиционными ФС режим работы. А когда позиционирования головок меньше - и работа быстрее. Скорость работы собственной ФС должна превзойти все остальные, правда при условии, пока файлы не фрагментированы.

Размер встроеных кешей будет определять поддержку только собственной ФС и FAT16. Ну, разумеется флопик и желательно CDFS. Поддержка других возможна подзагрузкой соответствующих модулей, со своим кешированием.

Обойтись без собственной ФС - нет подходящей кандидатуры. FAT16 для размеров современных дисков себя исчерпала, да и расходует дисковое пространство неэкономично. FAT32 экономичнее, но гораздо медленнее и может иметь гиганский FAT, что может быть нежелательно для задач которые требуют много памяти (виртуальная память в данной системе вообще не предусматривается). Предположим у вас диск 10G. Кластеров по 4К выходит больше 2,5М, да каждый элемент FAT 4 байта, вот вам 10М на один кеш, а кешей два...

Использовать ФС сетевых ОС - NTFS или от Linux? Они громоздки, там много ненужной в персональном компьютере информации о правах доступа и т.п., ведь они предназначены для многопользовательских систем.

Чисто психологически автору хотелось бы упихать всю системную часть в 640К первого мегабайта, чтоб прикладная задача размещалась начиная с первого мегабайта и судя по всему базовый вариант будет именно таков.

В стандартные дисковые драйвера войдут только IDE PCI Bus Master UDMA или DMA). SCSI если кто захочет, пусть делает сам, но будучи сделаным - можно его включить в систему как стандартный. Доступ к FLOPPY оставлен через BIOS 16-битным.

Видеокарта системой используется в текстовых режимах и уже сделана графическая эмуляция текста. Драйвера вероятны в пределах VBE. Остается стандартизировать функции. В целом это не трудно (включил видеорежим/выключил), но к сожалению неподдерживаемость производителями стандарта акселерации (VBE/AF) делает возможным ее использование только в случаях доставания правдами и неправдами описаний аппаратных регистров акселерации по каждой конкретной видеокарте и создания персональных драйверов. Информация эта у разработчиков довольно дорогостоящая, но вызовы все равно надо закладывать в проект.

Поддержка 16-битных драйверов (за исключением функций BIOS) и задач Real режима, через организацию виртуальной 16-битной машины, не планируется. Это потребовало бы сдублировать все функции DOS, а их предполагается наоборот - свести к возможному минимуму, и безо всякой совместимости.

Сперва создается загрузчик системы из под ДОС, с возможностью возврата. Это будет что-то вроде разновидности ДОС экстендера ориентированого на модель памяти и формат задачи новой ОС. В отличие от традиционных ДОС экстендеров, тут будет полный захват памяти и полное отсуствие ДОС поддержки, а все системные сервисы будут свои. Стандартными будут только функции BIOS. Это позволит уже на ранних этапах создавать прикладные задачи, правда ДОС компиляторами (все равно других пока нет).

Автор не претендует на лучшее знание всех сторон создания ОС. Ни одно из вышеприведеных положений не является догмой и готово к изменению в лучшую сторону.

Предлагается всем заинтересовавшимся этим проектом принять участие в обсуждении и выработке варианта годного к реализации.

Англоязычное общение возможно, хотя и не особо желательно, ибо по английски автор говорит примерно как Черномырдин по русски, т.е. много и охотно, однако понять сказаное до сих пор никому так и не удалось.

Данное описание набрасывает эскиз системы в общих чертах и будет крайне редкообновляемым.

Колесницкий В.М.

E-mail: kolesnitsky@caucasus.net


Last edited by Corvinus on 30 Jul 2007 10:45, edited 1 time in total.



30 Jul 2007 10:36
Profile
Fanat

Joined: 30 Jul 2007 10:31
Posts: 51
Reply with quote
Комментарий Алексея Вольского к пресловутой статье, а так же описание проекта эффективной многозадачной ОС E-Lite:

Quote:

Алексей Вольский (ayvo)

E-mail: ayvo@online.nsk.su

НЕСКОЛЬКО СЛОВ В ЗАЩИТУ МНОГОЗАДАЧНОСТИ

На самом деле, в Вашей статье практически ничего не сказано собственно про мультизадачность. Все претензии относятся к ее _конкретным реализациям_ на персональных компьютерах.

Собственно говоря, основных претензий две - страничный режим и защита по привилегиям. О них чуть ниже. Но в Вашей статье даже не упомянуты самые главные, на мой - и не только мой - взгляд, недостатки этих OS:

а) они ОЧЕНЬ ОЧЕНЬ БОЛЬШИЕ,

б) они очень плохо сделаны.

На среднем писюке под win95 только уровень vmm/vxd съедает порядка полутора мегабайт памяти. Добавим сюда дисковый кэш, совершенно бессмысленный в системе с виртуальной памятью. Добавим сюда просто ужасный код системных dll (посмотрите книжки Мэта Питрека "Внутренний мир Windows" и "Секреты системного программирования в Windows95). Для пользовательских программ просто не остается памяти.

Общим местом является то, что программы от MS имеют раздутый (bloat) интерфейс с множеством функций, которые подавляющим большинством пользователей никогда не используются. Но ведь то же самое можно сказать и об api win32 (и о сервисах vxd, если уж на то пошло). Фактически, никакого api нет. Есть множество разнородных функций, написанных "на всякий случай", многие из которых вообще ничего не делают.

Вообще говоря, помимо низкой квалификации большинства программистов, работавших над кодом windows, создается впечатление, что фирма microsoft страдает настоящим комплексом неполноценности. Многие вещи в windows обязаны своим появлением навязчивому желанию, "чтоб все было как у людей". Например, posix подсистема в NT, которую, насколько мне известно, не использует НИ ОДНА программа в мире.

На самом деле, конечно, этот комплекс во многом основан на чисто маретинговых соображениях. "В windows должен быть дисковый кэш, а то конкуренты убедят пользователей, что windows плохая. Исполняйте." И программисты исполняют. "Windows (по крайней мере, на словах) должна быть надежной. Плохие программы не должны заниматься вредительством." o'kay, накручиваем ужасающий bloat проверки параметров на каждую функцию api. "Но windows должна быть эффективной". o'kay, разрешаем kernel'у лазить в системные структуры кольца 0 (а значит и всем остальным тоже). И так далее, и так далее.

Так что низкая производительность windows программ очень в малой степени зависит от таких "мелочей", как страничное преобразование. Когда переключение цепочки занимает почти миллисекунду, поневоле разочаруешься в многозадачности вообще.

А как же Linux ? Здесь ситуация, кончено, лучше. Юниксойды и архитектуру имеют более разумную и написаны в основном не за зарплату. Но здесь вступает в игру другой фактор. Все юниксы - не персональные OS. Они с самого начала были ориентированы на МНОГОПОЛЬЗОВАТЕЛЬСКИЕ системы. Отсюда и определенные требования к защите (нельзя позволять игроку в неотлаженный тетрис завешивать почтовый сервер...). Отсюда необходимость в сложной файловой системе с приоритетами, правами и прочим. Кстати, стремление быть "похожими на unix" принесло все эти вещи и в мир wintel. Но следующие отсюда несуразицы несущественны по сравнению с бюрократической реализацией виндовоза.

Кроме того, в юнике тоже достаточно bloat. Гляньте хотя бы на код gcc. Это очень хороший пример - как не надо писать программы. (А вообще лучший компилятор всех времен и народов - это object pascal 32 из delphi... нет, я серьезно, посмотрите под дизассемблером, какой код он генерирует, и сравните с любым другим компилем

Но вернемся к unix. Наглядным примером bloat, вытекающим из многопользовательского характера unix, является X. Я не хочу сказать ничего плохого про ее авторов. X написана хорошо, так, как только и можно написать графическую подсистему для распределенной многопользовательской среды. Но перенос этого кода на персоналку ... ну, Вы меня понимаете.

Ну и на закуску. Unix написана очень давно. Хотя за прошедшие годы его неоднократно клепали, общая идеология осталась прежней. И это тоже дает о себе знать...

Короче говоря, на сегодняшний день нет достаточно распространенной os для персональных компьютеров, которая была бы тем, чем она должна быть.

Остаются, правда, еще некоторые штучки, вроде QNX. Судя по доступной информации, - это отличная os для i386up. Хотя потенциально она может обслуживать и распределенную среду, в силу настоящей микро-ядерной структуры и отличной модульности, вариант для одного пользователя с gui, текстовым редактором, браузером и проч. влазит на 1.44 дискету. Да, я понимаю, что это рекламный трюк. На самом деле, чтобы стать полноценной os, этому демо-варианту нужна, по крайней мере, поддержка какой-нибудь файловой системы и кое-какого железа (например, hdd). Но все равно, красиво. Беда только в том, что QNX - чисто коммерческая штучка, и за свои услуги - как всякая конфетка - берет дорого ;) И спереть ее (в отличие от windows) негде.

А все экспериментальные и исследовательские os вроде mach, vsta, L4 (это, собственно, микро-ядра) и проч. (весьма исчерпывающий список есть на cs.arizona.edu) опять-таки ориентированы на всяческие распределенные и супер-компьютерные применения. Вот такие дела.

Да, я еще обещал обсудить страничное преобразование и защиту. Увы мне. Придется выполнять. Итак, для чего в общедоступных os используется пагинация ?

* 1) для разделения адресных пространств отдельных задач (то бишь для защиты),
* 2) для связи между задачами (можно отразить что хочешь куда хочешь),
* 3) для увеличения объема доступной памяти.

Первые два пункта НЕ НУЖНЫ в персональной os. Этих же целей можно добиться более дешевыми средствами. По крайней мере, на i386up для этого вполне годятся селекторы. Защита на уровне селекторов очень устойчива против программных ошибок (при условии если обычной программе нет нужды часто загружать сегментные регистры), но бесполезна против злоумышленного вредительства (знаючи, например, селектор данных ядра всегда можно сделать какую-нибудь пакость). Страничное преобразование обеспечивает более надежную защиту. В cr3 пользовательская программа записать не может, а в кольцо 0 ей, теоретически, залезть не дадут (в обеих windows, конечно же, есть несколько дыр, как же без этого. Самая простая - использовать сервис dpmi для создания шлюза). Но в однопользовательской системе и незачем защищаться от вредителей ! Откуда им там взяться ? Разве-что вирус ... Но на то антивирусы и существуют.

Более серьезным соображением является увеличение объема памяти. Эта штука полезна на любой машине. Фактически, большинство нормально написанных windows прог сегодня вообще не проверяют out of memory error. Это здорово.

Но тут есть два момента. Во-первых, пагинация не решает проблему памяти кардинальным образом. Фактически, во всех известных мне os оверсвоп появляется уже при размере виртуальной памяти лишь вдвое превышающем размер физической. Собственно wintel системы без оверсвопа - это почти что исключение из правила. Так что все равно пямятишку бы неплохо докупить ... По нынешним временам, кстати, это весьма дешевая вешь.

А во-вторых, использование pagefile для увеличения объема памяти - это весьма и весьма опциональная вещь. По сути дела, работа ни одной из ключевых систем os не зависит от ее наличия (драйвер диска, конечно, должен страховаться, но и только). Мы, конечно, предполагаем, что пагер грузиться последним и виртуализует адреса только для пользовательских программ. Системные штуки-дрюки все фиксированы в памяти. Но они и так фиксированы во всех os с пагинацией (А как иначе ? А если кто-то перехватит прерывание ?) Windows, правда, теоретически разрешает vxd участвовать в свопе, но все vxd, которые действительно относятся к операционной системе (а не просто болтаются в кольце 0, как vwin32), сами себя фиксируют.

Итак, пагинация в персональной os - это просто один из возможных сервисов. Вроде дискового кэша в dos. Хочешь - включил pagefile.com в config.sys, хочешь - заремировал. 8(

Кстати, Вы где-то там сетуете, что менеджеры памяти не используют страниц по 4 мега (а есть еще ведь и 2-х меговые). Но такие страницы совершенно бессмысленны для подкачки. Их основное предназначение - фиксированные страницы (ядро, видеобуфер etc.) Идея заключается в том, чтобы уменьшить число TLB промахов. И, кстати, виндовоз это делает. Правда, довольно бестолково - перезагружая постоянно CR3 (в соседних кусках кода, вероятно написанных другим программистом в другое время).

Ну и пара слов о защите. Собственно, я уже все сказал выше, когда обсуждал защитные функции страничного преобразования. В персональной os нужна лишь защита от программных ошибок, которая эффективно выполняется при помощи разграничения доступа на основе селекторов. Так что все программы могут запросто выполняться в кольце 0.

Есть, правда, пара тонких моментов, связанных с обработкой некоторых искючений процессора. Все дело в стеке. Ошибку переполнения стека нельзя обработать без переключения стека. То же относиться к двойной ошибке и (oh, yeah) к INT OE (чито будет если инструкция PUSH обратиться к неприсутствующей странице? П..ц будет).

А самый простой способ добиться того, чтобы процессор переключил стек - смена привелегий. Тогда процессор возьмет новый стек из того, на что указывает TR (мультизадачные прибамбасы i386 можно и не использовать, а просто иметь fake tss, как это сделано в том же исходнике Tran'а. Кстати, известные мне модели 386-486 не проверяют предел tss до фактического переключения задачи, так что его размер можно и слегка подсократить). Но если все программы работают в кольце 0, то этот метод не сработает. При обработке прерываний уровень привелегий должен повышаться, а куда дальше то ?

Но это затруднение можно обойти, используя обработку нарушения стека в отдельной tss. Так как можно предполагать, что это исключение будет возникать достаточно редко, задумчивость intel-овских гипопотамов на этой операции не будет играть никакой роли. Двойная ошибка тоже бывает редко (да я уж надеюсь !). Пагинатор, правда, вызывается достаточно часто, но, во-первых, как мы уже определили выше, он опционален, если надо заняться чем-то серьезным (типа brute force attack на пароль вашего шефа :), его можно и вырубить. А во-вторых, Int 0E обычно кончается вызовом драйвера диска для чтения и, возможно, записи страницы, так что медлительность переключки (около микросекунды, см. у Григорьева) опять-таки никакой роли не играет.

Упф, рука бойцов колоть устала ! А ведь это только присказка, сказка будет впереди.

Архитектура операционной системы E-Lite

Микро-ядро

Элит - мультизадачная микроядерная система. Это означает, что одновременно выполняется несколько отдельных программ. При этом все системные сервисы, такие как драйверы аппаратуры, файловая система и т.д., представлены как отдельные задачи. Микро-ядро Элит обеспечивает взаимодействие между задачами и само реализовано как отдельная задача kern.

В каждый момент времени задача может находится в одном из следующих состояний:

* ts_init - задача создана, но еще не работает
* ts_exec - задача готова к выполнению
* ts_recv - задача ожидает сообщение
* ts_send - задача ожидает ответа на сообщение
* ts_dead - задача уже не работает, но запись о ней еще
не удалена (foot text="В Unix это называется zombie state")

Приоритеты

Каждая задача в системе имеет свой приоритет - уникальное число в диапазоне от нуля до максимального числа задач в системе минус один (по умолчанию в Элит одновременно может существовать 64 задачи, однако, их число может быть увеличено до 256).

В каждый момент времени выполняется задача, имеющая максимальный приоритет (то есть наименьшее значение приоритетного числа). Все остальные задачи, потенциально готовые к выполнению, будут ожидать пока текущая задача не отдаст процессор. Однако, более приоритетная задача может отобрать управление у текущей в результате прерывания.

Таким образом, Элит хорошо подходит для приложений реального времени (учитывая, что Элит предназначена для персональных компьютеров, это в основном игрушки и мультимедиа). Если задача имеет высокий приоритет, отобрать у нее процессор смогут лишь несколько еще более приоритеных системных сервисов, активацию которых задача может проконтролировать (например, драйвер ввода-вывода активируется только если задача к нему обратится).

Приоритет, который имеет задача, определяется двумя параметрами - типом задачи (задаваемом в управляющем слове программы PCW) и порядком запуска задач. Всего существует четыре типа задач:

* pri_serv - системный сервис, наивысший приоритет
* pri_real - задача реального времени
* pri_user - пользовательская задача
* pri_idle - пассивная задача, активируется только когда нет других более приоритетных задач, низший приоритет

Когда задача запускается на выполнение, она получает первый свободный приоритет данного класса. По умолчанию число доступных приоритетов каждого класса таково:

* pri_serv - 20 (0-19)
* pri_real - 1 (20)
* pri_user - 42 (21-62)
* pri_idle - 1 (63)

Однако, эти диапазоны могут быть переконфигурированы. Например, если используемые программы реального времени не очень-то "реальны" и фактически их можно запускать на пару, пользователь может увеличить диапазон ts_real. Обратно, если в системе меньше 20 системных сервисов, их диапаон можно сузить.

Заметим также, что далеко не все системные сервисы требуют высокого приоритета. Например, модуль tcp/ip или файловая система могут (и должны быть) реализованы с приоритетом pri_user. Поскольку такие задачи стартуют раньше, чем обычные пользовательские задачи, они будут иметь достаточный приоритет. Класс pri_serv требуется в основном лишь драйверам, непосредственно работающим с физическими устройствами компьютера (где имеется жесткая зависимость по времени).

Защита

Механизм защиты, встроенный в Элит, ориентирован на персональные - однопользовательские - системы. Используемые средства позволяют предохранить систему от последствий ошибок в пользовательских программах, но не от злонамеренных действий.

Основным средством защиты являются адресные пространства (см. ниже), раздельные для всех задач. Однако, этот механизм реализован не на страничной модели памяти, а на использовании сегментов. Нормальная программа никогда не изменяет сегментных регистров, поэтому никакая ошибка в ней не может привести к записи в чужое адресное пространство (вероятность случайной передачи управления на данные, которые могут быть проинтерпретированы как что-нибудь вроде "pop ds", практически нулевая). Однако, при желании задача _может_ загрузить в любой из сегментных регистров любое значение.

То же самое касается и изменения различных системных ресурсов. Поскольку все задачи выполняются в кольце 0 (защита по привелегиям x86 не используется), любая программа может выполнять инструкции типа "lidt", "mov cr0,0" или записать пару байт в порт 20h ... Но обычная программа этого не делает, и поэтому, не может сделать этого и по ошибке.

Таким образом, в Элит не приходится расплачиваться за надежность существенным ухудшением производительности, как в других "персональных" операционных системах для x86. С другой стороны, такой подход к защите не позволяет применять Элит для многопользовательских систем, где необходимо обеспечивать защиту от "вредительских" программ.

Адресные пространства

Каждая задача выполняется в отдельном адресном пространстве памяти и не видит пространства других задач. Пространства памяти реализваны на основе сегментной модели процессора x86 - каждая задача имеет один селектор данных, загружаемый в регистры DS, ES и SS, и один селектор кода, загружаемый, естественно, в регистр CS. Линейныйе адреса и пределы всех этих сегментов совпадают.

Таким образом, каждая задача владеет непрерывным участком памяти, внутри которого она может делать все что захочет - выполнять данные как код, вносить исправления в свой код, располагать стек в любом удобном месте и т.п. Все это никак не может отразиться на остальных задачах в системе.

Исходный размер адресного пространства задачи определяется старшими 20 битами слова управления программы, которые задают число страниц памяти по 4k каждая, которые необходимо выделить программе. В младшие адреса этого пространства копируется образ программы из файла, а указатель стека устанавливается на конец пространства. В дальнейшем программа может свободно изменить как расположение отдельных своих частей внутри адресного пространства, так и изменить размер выделенного ей блока памяти. Последнее выполняется при помощи посылки соответствующих сообщений микро-ядру.

Надо учитывать, что хотя каждой задаче соответствует какое-то адресное пространство, далеко не всякое пространство содержит в себе задачу. Адресные пространства можно создавать при помощи посылки соответсвующих сообщений микро-ядру. Таким способом, например, резервируется память видеоадаптера и т.п.

Программы

В связи с разделением адресных пространств видимая каждой задачей память всегда начинается по адресу 0. Это позволяет максимально упростить внутренний формат программного файла. Фактически, он эквивалентен тому, что в dos называлось com-файлом.

Вся внутренняя структура состоит из управляющего слова программы (PCW). {foot text = "На самом деле, это двойное слово в терминологии интеловских бегемотов. Но на любом другом процессоре базовая единица памяти называется словом."} Это слово определяет основные характеристики программы и имеет следующий формат:

* начальный размер адресного пространства в страницах (20 бит),
* класс приоритета (2 бита),
* может ли адресное пространство участвовать в свопинге (1 бит),
* должны ли линейные адреса соответствовать физическим (1 бит),
* зарезервировано (8 бит).

Размер адресного пространства, как уже говорилось, затем может меняться программой по мере необходимости. Точно также, программа в дальнейшем может разрешить своп для некоторых своих страниц, послав соответсвующее сообщение менеджеру страниц (если он тут есть).

Взаимодействие между задачами

Для обеспечения связи между задачами микро-ядро предоставляет несколько примитивов, реализующих обмен сообщениями. Для посылки сообщения задача может использовать два варианта:

* post() - асинхронная посылка, и
* send() - посылка с ожиданием ответа.

Во втором случае задача переходит в состояние ts_send и не будет выполняться до тех пор, пока получатель сообщения не вызовет reply(). В случае же post() задача- получатель сообщения активируется только если ее приоритет выше, чем у текущей. В любом случае при использовании post() задача-отправитель остается в состоянии ts_exec и будет выполняться, как только не будет более приоритетных задач.

Вариант с send() больше подходит для ситуаций, когда одна задача запрашивает обслуживание у другой (модель клиент- сервер). По такому принципу реализован ввод-вывод. Когда задача хочет что-нибудь записать на диск, она посылает соответствуюий запрос драйверу жесткого диска, который в свою очередь, выполнив операцию, информрует клиента о результатах при помощи reply().

Алгоритм post() больше подходит для информирования задачи о некотором событии, которого может и не быть. Например, клавиатурные сообщения пересылаются в текщую задачу, владеющую фокусом ввода, именно при помощи post().

Системные сервисы в основном должны пользоваться post(), когда они взаимодействуют с менее приоритетными задачами. В противном случае, пользовательская задача, "не читающая почту" может заблокировать системный сервис в состоянии ts_send на неопределенное время.

Чтобы получить сообщение, задача должна сделать вызов recv(). Если имеется подходящее сообщение, оно будет возвращено и задача продолжит выполнение. Если же такого сообщения нет, задача перейдет в состояние ts_recv, в котором и будет пребывать до тех пор, пока кто-нибудь не пришлет ей сообщение, соответсвующее маске запроса.

После обработки сообщения задача должна вызвать reply().

Если соответствующее сообщение было послано при помощи send(), этот вызов разблокирует отправителя (переведет его в состояние ts_exec) и передаст ему результаты обработки. Если же отправитель использовал post(), вызов reply() не делает ничего. Теоретически, задача может не отвечать на сообщение, если она абсолютно уверена в том, что это сообщение послано асинхронно. Однако, по соображениям надежности всегда лучше вызывать reply().

Заметим, что механизм сообщений представляет собой единственное средство синхронизации между задачами. Это снимает все проблемы, связанные с разделяемыми ресурсами, взаимной блокировкой и т.д. Всякий разделяемый ресурс в системе оформляется как отдельная задача и обращения к нему буферизуются при помощи send() или post().

Чтобы послать сообщение другой задаче, необходимо знать ее идентификатор. Для некоторых основных задач, которые всегда есть в системе, идентификаторы известны заранее. Другие назначаются динамически. Для установления связи между такими задачами используется механизм публикации. Существует специальная задача - сервер имен (это самая заурядная задача класса pri_user). Задачи, желающие предоставить в общее пользование какой-либо сервис, регистрируют себя под каким- либо символьным именем, а клиенты по этому имени узнают идентификатор сервера. Вот как, например, можно пристегнуть файловую систему к драйверу CD-ROM.

atapi-cd /name=teac36 ;говорим CD зарегистрироваться как teac36
cdfsd /cd=teac36 /name=cdrom ;говрим FS использовать этот драйвер

Прерывания

Другим механизмом изменения состояния задачи являются прерывания. Они используются для синхронизации с внешними (обычно аппаратными) событиями. Важно учитывать, что функция обработки прерывания активируется в контексте текущей задачи, а не той, которая установила этот обработчик прерывания.

Такой подход позволяет упростить схему диспетчеризации прерываний, а значит - уменьшить время реакции на прерывание. Типичный обработчик прерывания должен выполнить все действия, критичные по времени, а затем - если нужно - активировать свою собственную задачу.

Для синхронизации задачи с установленными ей обработчиками прерываний используются те же самые post()/recv(). То есть обработчик прерывания от имени текущей задачи посылает сообщение своей. Если последняя имеет более высокий приоритет, текущая задача отдаст процессор до лучших времен.

А как обработчик может найти свою задачу ? По собственному селектору кода. Посколько селекторы кода и данных для каждого адресного пространства имеют одинаковые линейные адреса, обработчик может прочитать всю нужную ему информацию (например, идентификатор своей задачи, сохраненный в глобальной переменной), используя префикс замены сегмента CS.

Режим разделения времени

Описанная выше жесткая схема приоритетов хорошо подходит для планирования системных и критичных по времени приложений. Однако, она не очень удобна для большинства диалоговых программ. Допустим, пользователь последовательно запускает программы А и Б, после чего переключает фокус ввода на А. Теперь он уже не сможет переключиться обратно к Б до тех пор, пока А не перейдет в состояние, отличное от ts_exec, так как у А приоритет выше.

На самом деле, так как любая диалоговая пограмма постоянно запрашивает обслуживание у других задач, и большую часть времени ожидает пользовательского ввода, в большинстве случаев эта блокировка не заметна для пользователя. Но если в нашем примере программа А займется чем-нибудь вроде вычисления благоприятного для женитьбы расположения звезд в римановском пространстве произвольной размерности, Б окажется блокированной...

Данную проблему можно решить на уровне самой программы. В данном примере программа А (астролог) могла бы создать новую задачу с и поручить ей всю грязную работу (ниже всех pri_user задач), а сама вернуться к диалогу с пользователем. Однако, отслеживание в программе всех мест, где теоретически может возникнуть длительная блокировка, достаточно нетривиальное занятие. В любом случае операционная система не может полагаться на пользовательские программы в таком важном вопросе...

Поэтому требуется некий механизм смены одной задачи другой по тайм-ауту. Этот механизм обеспечивается менеджером задач. Он представляет собой просто обработчик прерывания от таймера, запрограммированного на генерацию периодических (допустим, 20 раз в секунду) прерываний.

Каждый раз, когда обработчик активируется, он проверяет - имеет ли текущая задача класс приоритета pri_user. Если да, он посылает создаваемой при старте системы задаче idle (с самым низким приоритетом из возможных) {foot text="Такая задача все равно нужна при используемом механизме планировки"} какое-нибудь сообщение при помощи send(), снимая таким образом текущую задачу с процессора и передавая управление следующей активной.

Когда больше не останется активных задач, выполняться начнет idle (больше некому). Его действие по умолчанию заключается в чтении всей приходящей ему почты и вызове reply(), сообщающем об ошибке {foot text="Это опять-таки надо, чтобы майл-бокс idle не засорялся возможными ошибочными посылками. У других программ такой проблемы нет, т.к. они выполняют какие-то функции и, следовательно, читают свою почту осмысленно."}.

Но ответ на сообщение, посланное менеджером задач, приведет к активации той задачи, от имени которой это сообщение посылалось. И все пойдет по кругу. Задача работает, снимается с процессора, активируется idle, читает очередное сообщение, активируется следующая задача, работает, засыпает и т.д., и т.д. Таким образом, происходит циклическая смена пользовательских задач. Заметим, что поскольку менеджер задач переводит текущую задачу в состояние ts_send, ротация не нарушает базового принципа - всегда выполняется задача с наивысшим приоритетом _из числа готовых_ к выполнению.

Приложения, критичные к времени выполнения

Существует небольщой класс задач, которые не могут выполняться в режиме разделения времени (это игрушки, обработка мультимедиа, а также некоторые "долгоиграющие" математические моделяторы). Обычно подобные задачи также предъявляют и повышенные требования к использованию системных ресурсов.

В Элит они относятся к классу pri_real. Так как их приоритет выше, чем у пользовательских задач, они будут выполняться немедленно, как только будут готовы к этому. Прервать их может только какой-нибудь системный сервис. Но системные сервисы не активируются без причины. Если нет прерываний от аппаратуры и нет запросов на обслуживание, они мирно спят (ts_recv). А поскольку текущая задача имеет статус ts_real, она может быть уверена, что никто кроме нее не вызовет системный сервис (одновременный запуск нескольких риалтаймовских приложений оставим на совести пользователя, если его все устраивает - почему нет ? "Ну, дергается маленько экран...")

Фактически, задача класса ts_real может полностью монополизировать компьютер (железо + системные сервисы). Например, так:

struct mail msg;

msg.dest = kern;
msg.link = kern_memmgr;
msg.what = kmm_realloc; //изменить address space текущей задачи
msg.data = 0;
msg.info = 0xFFFFFFFF; //вся доступная память
if(send(msg) == e_fault) exit(1);

msg.dest = pagefile;
msg.link = page_ioctl;
msg.what = pg_disable; //предполагается, что в PCW программы
msg.data = 0; //установлены биты cw_fixed и cw_mirror
msg.info = 0;
if(send(msg) == e_fault) exit(1);

msg.dest = kern;
msg.link = kern_irqmgr;
msg.what = irq_disable;
msg.data = 0;
msg.info = 0xFFFF; //все 16 каналов
if(send(msg) == e_fault) exit(1);

Вуаля! Мы владеем всей доступной памятью в системе. Своппинг отключен. Прерывания закрыты. Мы их будем открывать по мере необходимости. Пользователь может смело кидать валенок на пульт. Все под контролем. Естественно, подобного рода программа берет на себя всю ответственность за то, что будет дальше. На некоторых чипсетах, например, запрет канала 2 PIC завешивает регенерацию памяти (они думают, что поскольку в стандартном AT это каскад, его можно использовать для своих нужд). Но если так надо, мы _можем_ это сделать. Элит этому не помешает. Важно лишь, что _по ошибке_ подобный код выполниться не может. А если программа делает такие штуки сознательно - флаг ей в руки ...

Скорость реакции системы

Механизм send()/recv() является базой всех микроядерных os. Однако, несмотря на его простоту и логичность, во всех известных ядрах, портированных на i386up, он довольно-таки неэффективен в связи с высокими накладными расходами. Это объясняется тем, что вызов этих примитивов ядра подвешивается на какое-нибудь прерывание. Добавим сюда обычную смену привелегий ... И вот посылка сообщения уже тратит почти микросекунду только на int/iret (со сменой привелегий минимум 71 и 36 тактов соответственно, если Григорьев не врет). Далее требуется переключение задачи. Поскольку обычно используется tss - еще микросекунда. Далее требуется перепланировка - сложный планировшик с динамическим приоритетом - еще пара микросекунд. Ну и сам код со всякими прибамбасами типа записи статистики для последующего использования планировшиком - еще микросекунда (считая по 10ns на инструкцию). Да все это написано на Си. И так на каждом сообщении.

Совершенно очевидно (мне, по крайней мере), что для Элит такая стратегия не годится. Базовые системные примитивы должны выполняться _очень_ быстро. От их оптимизации будет зависеть производительность всей системы. Каждый лишний такт здесь обернется потерянными часами для всей системы (ну это я загнул конечно).

Основная идея состоит в следующем. Истинное микро-ядро (т.е. send, post, recv, reply и еще парочка примитивов, также отвечающих за IPC) находятся в начале адрессного пространства КАЖДОЙ задачи. Любая программа компилируется с базового адреса в 1k (ORG 400h). При загрузке в память, загрузчик копирует в этот промежуток первый килобайт из _своего_ собственного адресного пространства (а туда он в свою очередь заносится ядром - эдакий PSP). Вызов примитивов происходит косвенно через память - в самом начале ядреного килобайта лежит небольшая таблица переходов. Ближний вызов через память - это всего 5 тактов.

Таким образом, эти несколько функций не вшиты в пользовательские программы и могут быть изменены при изменении внутренних структур ядра. Кстати, а как эти функции могут получить доступ к тем самым структурам ? Просто:

mov ax,kern_data_selector
mov gs,ax
Переключение задачи также осуществляется очень быстро:
lss gs:[edi][task_stack]
...
iret

Фактически из всех задумчивых команд процессора используется одна единственная IRET (около 15 тактов). Адрес, по которому она переходит, сохраняется не при помощи еще более медлительных INT и CALL FAR, а через:

pushfd
cli ;далее пойдет обращение к структурам ядра
push cs
push ret_address

Заметим, что так реализованы лишь ключевые примитивы ядра. Более сложная и менее критичная по времени поддержка системных структур (например, создание селекторов) реализована как посылка сообщений отдельной задаче kern.

Эта оптимизация практически не уменьшает защищенности системы. Если программа затрет свой первый килобайт, - плохо будет ей одной (у всех остальных свои локальные копии этого кода). По ошибке обратиться к системным данным она тоже не может, т.к. регистр GS зарезервирован за системой и обычные программы никогда к нему не обращаются за пределами кода в ядреном килобайте. Можно, конечно, представить себе сценарий, при котором пошедшая вразнос программа передаст управление куда-нибудь в середину send, но если это место будет находится до загрузки регистра GS, то наихудший вариант будет заключаться в посылке неверного сообщения, которое должно быть отфильтровано получателем (sanity check). Если же управление попадет на команду после инструкции, загружающей GS, любая попытка его использования приведет к GP, т.к. за пределами микро-ядра GS всегда содержит 0. Вариантом, когда программа западет в аккурат на "mov gs,ax" можно пренебречь как крайне мало вероятным (ведь помимо этого в ax должен еще содержаться действительный селектор).

Имеющиеся недостатки

Этой операционной системы не существует. :( :( :(

Есть несколько эскизов. Есть скелет компилятора с чего-то напоминающего Си с классами в стиле delphi pascal (а не С++). Все же скучно писать os на ассемблере. Вон некоторые уже в своем дебуге, говорят, ничего понять не могут :) Есть много идей (Идея фикс: реакция системы должна быть как в транспьютере - 640ns). Есть этот проект ...

Comments are welcomed !


30 Jul 2007 10:43
Profile
Fanat

Joined: 30 Jul 2007 10:31
Posts: 51
Reply with quote
Dos Extender в ИСХОДНЫХ ТЕКСТАХ со встроенным отладчиком, который позволит вам монополизировать все ресурсы процессора и памяти для решения ОДНОЙ задачи в 32-битном защищенном режиме процессора, и к тому же бесплатный.
В настоящее время вытесняется проектом ОС.
Версия от 12 мая 2000г.

[quote]DOS Extender for 32-Bit Protected Mode with embedded DEBUGGER

Предлагаются ИСХОДНЫЕ ТЕКСТЫ Dos Extender-а приведенного к своему простейшему состоянию, а именно: Flat Memory, Запрещенное страничное преобразование, Уровень привилегий 0 (Высший), и главное встроенный Отладчик. Большое внимание уделено регистрам и состоянию сопроцессора.

Все что нужно для работы - TASM 5.0 и хотя бы небольшие навыки в его использовании, процессор 486 или лучше, обязательно с сопроцессором. Весь TASM ставить нет необходимости. Достаточно следующих файлов:

    tasmx.exe
    tlink.exe
    rtm.exe
    dpmi16bi.ovl


что позволяет в экзотических ситуациях компилировать задачу даже на машине лишенной Hard диска. На обычной дискете прекрасно умещаются: DOS, VC, TASM, все исходные тексты и obj, а в случае нужды WASM и еще остается место.

Теперь плохие новости - программа работоспособна ТОЛЬКО ПОД DOS,т.е. требует Real режим процессора. Стартовать ее из под Windows даже в режиме MsDos Prompt, который представляет собой режим Виртуальной 16-разрядной машины невозможно. Более того, проблемы будут даже в DOS, а именно HIMEM.SYS не должно быть даже духу, конкурентов в управлении Extended memory программа не терпит. В Dos 6.22 достаточно выкинуть его из config.sys, но в Windows 95 Command Prompt он загружается автоматически и автору приходилось использовать пошаговую загрузку, когда не сохранялась возможность загрузки старой версии Dos. Еще более удобным вариантом является создание простейшего собственного Boot Manager-а который держит загрузку постоянно либо в Dos, либо в Windows не задавая при включении компьютера лишних вопросов. Как его сделать, описано в каталоге BOOTMNGR. Правда работать с FAT32 из старого Dos невозможно, он просто не увидит Hard. Впрочем, несовместимость с Himem.sys можно снять, дописав соответствующий кусочек, контролирующий, сколько занято extended memory и устанавливающий константу _himembase на начало свободной памяти, но это противоречит убеждению автора - все ресурсы, особенно памяти должны монополизироваться программой, да и распределять память выше первого мегабайта приходиться вручную, ассемблер тут не помощник, и сдвиг начального адреса создаст большое неудобство, особенно если создавать свои дескрипторы. Дело в том что работа в адресном пространстве выше первого мегабайта ведется с АБСОЛЮТНЫМ адресом, а в традиционном программировании для PC - адреса как правило относительны, что делает программу позиционно независимой. Здесь же это правило справедливо только в пределах первого мегабайта. Впрочем, пока вся Extended память доступна, особых неудобств от этого нет.

Те, кто хорошо представляет себе работу в Protected mode, ниже приведенные разглагольствования могут пропустить и перейти сразу к части ОПИСАНИЕ, тем более что все приведенное ниже гораздо подробнее рассмотрено в отдельной статье, целиком посвященной тому, что автор думает о многозадачности вообще и о Windows в частности.

Увы - 32 битного Dos-а не существует, и существовать тем более не может, так как Dos - ОДНОЗАДАЧНАЯ операционная система сугубо РЕАЛЬНОГО режима, а работать с 32-битным адресом на процессорах фирмы INTEL возможно только ЗАЩИЩЕННОМ (он же Protected) режиме, который к тому же предполагает многозадачность. Исключение режима 32 - bit Real остается оставить на совести INTEL (хотя автор и выражает сомнение, что таковая у упомянутой фирмы имеется). Реальный же режим остался 16-битным как у старой доброй XT. 16-битного защищенного режима, как и равно 16-битного режима виртуальных машин мы касаться не будем.

Что же представляет собой защищенный режим. Ну то, что смещение (а это и есть тот самый живой или логический адрес, с которым приходиться работать программисту) стало 32 битным - это ежу понятно. Хуже обстоит дело с сегментами (это регистры CS:,DS:,SS:,ES:,FS:,GS: которые в любом режиме остаются 16 битными ), они теперь сами адрес не формируют, а поменяв название превратились в селекторы сегментов и адресуют 64 битные элементы в так называемой Дескрипторной таблице и которые так и называются Дескрипторы сегментов. Дескриптор задает начальную позицию в 4Г физической памяти, размер сегмента с шагом 4К, тип сегмента (код, данные, стек), присутствие и т.п., кроме разумеется того, что нужно (по мнению автора). Логический адрес суммируется с базовым адресом начала сегмента (в данной программе его можно узнать по имени _code32a) и получается физический адрес, который и выдается на шину процессора.

Но тут жизнь осложняет многозадачность. Дескрипторные таблицы бывают - одна глобальная (обычно для операционной системы) и много локальных (по одной для каждой задачи). В данной программе Дескрипторная таблица всего одна, очень маленькая, но очень глобальная. Однако мучения процессора в формировании адреса во всех многозадачных операционных системах на этом не заканчиваются. Между логическим и физическим адресами влезает страничное преобразование которое формирует промежуточный так называемый линейный адрес (данная программа от этого, слава богу, избавлена). На кой чорт оно нужно ? Именно оно порождает пресловутые разделяемые библиотеки DLL в Windows. Вся доступная физическая память делится на куски по 4К которые с помощью таблицы страниц (очень похожей на Дескрипторную таблицу) могут отображаться на разные логические адреса. В физической памяти располагается ОДНА разделяемая библиотека, которая отображается в логические адреса десятка разных задач и каждая задача считает ее своей персональной библиотекой. На этом экономится память кодов, но это еще не все. Страницы можно отобразить на несуществующую память расположив ее например, на Hard диске. В случае обращения к такой, так называемой неприсутствующей странице возникает прерывание и операционная система переносит ее с Hard-а в оперативную память, а те страницы, к которым, по мнению системы нет обращений она выкидывает на Hard освобождая память. Это и есть Виртуальная память, а файл неиспользуемых страниц - Swap-файл или файл подкачки. Но за все нужно платить и Pentium с вычислительной мощью суперкомпьютеров прошлых лет стоивших сотни миллионов долларов превратился, правда, в очень хорошую пишущую машинку, которая складывает два числа дольше, чем это делает ученик 1 класса. Дело в том, что существующие операционные системы Windows 95, NT, OS/2 по своей сущности - системы для офисного применения, т.е. им не важна производительность за нее пусть отдувается процессор даром что у него сотни мегагерц, а важно кто обеспечит пользователю наибольший сервис и богатство возможностей. Продаваемость множества математических пакетов и моделирования для этих систем, скорее дань рекламе, чем их использования для действительно интенсивных математических расчетов (а при хорошей рекламе, как известно вода из-под крана продается ничуть не хуже нефти). В какой-то степени лучше дело обстоит у UNIX подобных систем, в частности Linux за счет того, что у них на все от начала до конца есть исходные тексты и ядро системы можно создавать по своему усмотрению, впрочем, автор мало знаком с этими системами и толково судить о них не берется.
Почему же автор так не любит режим страничного преобразования адреса? Дело в том, что существует круг счетных задач, где страничное преобразование может очень сильно понизить производительность. Это задачи обработки больших массивов (десятки мегабайт) данных. Приведу пример: кеш страниц Pentium Pro - 512 страниц (сама таблица хранится в памяти, но в процессоре для нее создан свой кеш, не имеющий ничего общего с кешем общего назначения, у 486 он был 32 страницы, и еще - имеются в виду не содержимое страницы, а ее описатель подобный дескриптору). При размере страницы 4К это 2М памяти (у Pentium добавлены страницы по 4M но операционные системы используют их, как правило, только для адресации видеопамяти) Записываем в память двумерный байтный массив с размером строки больше 4К и числом столбцов больше 512 (общий размер больше 2М). Причем записываем по строкам. Адреса в памяти в этом случае следуют подряд и подкачка новой страницы происходит 1 раз за 4096 операций записи. Потерь времени можно считать не происходит. Но прочтем этот массив по столбцам. Каждая операция чтения -обращение к новой странице т.к. строка больше 4К, кеш страниц не работает т.к. строк больше 512 и он переполнен. Следовательно, страница (точнее 32 битный элемент таблицы страниц) должна читаться из основной памяти, а это очень долго (кеш память общего назначения, правда, исправляет ситуацию беря на себя 7 из 8 обращений, но каждое 8 потребует 4 цикла считывания для заполнения строки кеш, что кстати SDRAM делает быстрее DRAM, выполняя первый цикл с такой же скоростью как DRAM, а три последующих гораздо быстрее). Самое удивительное - что в этом примере кеш память первого уровня - ПОНИЖАЕТ быстродействие (со страничным преобразованием это уже не связано). Судите сами. Массив больше кеша - кеш переполнен (кеш первого уровня размером 16К содержит 512 строк по 32 байта). При обращение к каждому последующему БАЙТУ массива в кеше не оказывается достоверной строки, что вызывает заполнение всей строки т.е. 4 цикла чтения вместо необходимого одного. При определенных размерах массива эта же участь постигнет и кеш второго уровня. Правда, элементы таблицы страниц позволяют вам запретить кеш память, но ни одна операционная система не дает вам доступа к этой таблице. Лучшим выходом было бы запрещение кеш памяти на уровне дескрипторов (загружаете такой дескриптор в малоиспользуемый сегментный регистр FS: или GS: и через него обращаетесь к памяти), но INTEL не предоставила такую возможность дескрипторам, за что автор и катит на нее бочку.
Следующая мерзопакостная вещь порожденная многозадачностью - уровни привилегий. Их у процессора 4. Единственный приличный 0 (Высший) - выполняются любые команды процессора. Во всех многозадачных операционных системах и, что автору вообще не понятно, в Dos Extender-ах Watcom C++, NDP C++, у пользователя самый низший уровень привилегий 3. С уровнем привилегий также связано выполнение операций ввода-вывода и разрешения-запрещения прерываний, правда, здесь этот уровень можно менять программно, но только операционной системе. Естественно, что эти операции для пользователя запрещены. Попробуйте в Windows считать или записать что-то в порт - система тут же вас выплюнет с диагнозом Нарушение общей защиты - только через драйвер, у которого уровень привилегий выше. А обращение к драйверу, это переключение задачи, это прохождение шлюзов (а вдруг это злодей пытается пролезть на более высокий уровень привилегий). Низший уровень привилегий у вышеупомянутых и в общем-то однозадачных Dos Extender-ов - загадка для автора - с кем ресурсы то делить, от кого защищаться ? Вы наверно уже догадались, что у предлагаемой программы уровень привилегий 0 (впрочем, если вам хочется, можете его понизить - исходник под рукой).
Может возникнуть еще один вопрос. Почему не создали 32 битный ОДНОЗАДАЧНЫЙ Dos работающий в Защищенном режиме подобно старому 16 битному ?
Теоретических препятствий к этому нет, есть практические и главное из них BIOS. Он по своей сущности был и остается 16 разрядным, а ведь именно через него идет все взаимодействие с периферийным оборудованием. В полностью 32 разрядных системах, например Windows NT с BIOS вообще никакой работы не ведется, все идет через 32 битные драйвера. Поставщики оборудования естественно не будут снабжать свои платы драйверами для операционной системы занимающей доли процента от всего рынка. Dos Extender-ам приходится производить операции ввода-вывода через 16 разрядные подпрограммы BIOS и о какой либо производительности здесь говорить не приходится. Впрочем, имея достаточно автономный (т.е. не обращающийся в процессе работы к ядру операционной системы) драйвер с известными точками входа и передаваемыми параметрами, автор не видит особых проблем для подключения их к описываемой программе. Проблема в том, что драйверов полно -информации по ним нет. (полноценный драйвер Hard диска написан и включен в комплект поставки) Однако надо отдать должное в BIOS современных машин есть один участок работающий в Защищенном режиме. Это так называемый BIOS32 Directory Service - управление конфигурацией PCI устройств.

Спецификацией по нему, можно разжиться на этой же страничке Данная программа позволяет проводить с BIOS32 всевозможные эксперименты.

Видеосистема, наконец, начала уходить в полноценную 32-битность, не привязанную к конкретной ОС, что вообще-то необходимо было сделать сразу с появлением PCI шины. BIOS видеокарт начали расширять VESA стандарты, поначалу ограничивающиеся только добавлением новых видеорежимов. Но, начиная с версии 2.0 стало, наконец, возможным включить всю видеопамять карты в общее адресное пространство одним нефрагментированным куском. Это режим т.н. LFB (Linear/Flat Frame Buffer). До его появления, если у вас не было драйверов под вашу систему, приходилось упихивать мегабайты видеопамяти в 128К отведенные на эти цели более 20 лет назад. Добавились функции дублирующие основные, но выполненные целиком в 32-битных кодах. Есть ссылки и на то, что наконец станет доступной акселерация. Более подробно о работе с функциями VESA можно прочитать в статьях С.А. Андрианова в журнале "Мир ПК" номера 7 и 8 за 1998г, которые имеются в Интернет на www.osp.ru/pcworld. Примеры их использования можно найти и в некоммерческой версии TMT Pascal. Сами стандарты можно отыскать на страничке www.halyava.ru/document/ind_hard.htm Толкового учебника по ассемблеру для защищенного режима посоветовать не могу, потому что такового сам не встречал. Книжки с надписью АССЕМБЛЕР попадающиеся в продаже посвящены несчастному 16-bit Real режиму и кроме как макулатура ценности из себя не представляют. Лучшее, что есть на сегодняшний день - двухтомник В.Л. Григорьева "Микропроцессор i486. Архитектура и программирование" совместного издательства "Бином и Гранал" - 1993г. Но это все же не учебник, а справочное руководство, зато в нем о процессоре есть ВСЕ (описание незначительных отличий Pentium-а, например команды CMPXCHG8B или команд MMX лучше получить с серверов Intel или AMD). Правда, из продажи он практически исчез, но эту же книгу в виде файлов можно найти на многочисленных (но, разумеется, исключительно "левых") лазерных дисках, где собраны всевозможные компиляторы, если там будет раздел - "Документация для программиста". Как правило, все эти коллекции из одной бочки и практически копия упомянутой книги находится в каталоге (или выражаясь как Windows 95 в ФОЛДЕРЕ) INTEL486 или неформатированный вариант I486. Наибольший интерес представляет ее последняя часть - справочник по системе команд включающий описание способов адресации. А ведь главное отличие работы в защищенном режиме совершенно другие способы адресации с применением любых понравившихся (а не назначенных команде) регистров (например MOV EDX,[ECX][EAX*8]+322 и все это одна команда, а если заменить MOV на LEA то команда умножит один регистр на 8 (4,2 или оставит как есть), затем то, что получится, перемножит со вторым регистром, прибавит константу и все это загрузит в третий регистр (получатель)). На упоминавшемся диске можно разжиться и описанием TASM 2.0 хотя по рукам ходит и 3.0 (оба на русском).

ОПИСАНИЕ

Речь пойдет главным образом о последней части пышного заголовка предваряющего этот текст - а именно об отладчике, к коему автор имеет самое непосредственное отношение - он их (этот текст и отладчик) написал. Сам DOS Extender создал очень давно (судя по дате еще в 1993 году) Tom Pytel, впоследствии участник создания некоторых очень популярных игр. Его оригинал находиться в каталоге TRAN1993. Изменений в него внесено немного, главным образом сделаны добавления. Имена измененных файлов оставлены старые, так что одноименные файлы в разных каталогах могут не совпадать по своему содержимому. Отладчик рассчитан на стандартный текстовый режим 80x25 и на графический VESA 1024x768x16 (единственный видеорежим высокого разрешения который "упихивался" в 128К первого мегабайта, да и тот плохо работает на дорогих видеокартах и совсем не работает на очень дорогих (с всевозможными видеокартами S3Trio проблем нет). На момент создания Dos Extender-а спецификация VBE 2.0 была недоступна и про возможность включения LFB ничего не было известно. Впрочем, для построения графиков данный видеорежим с его работой в независимых плоскостях довольно удобен.

При старте программы, первый вызов отладчика происходит по команде INT 1 втыкаемой в текст программы либо самой первой, либо в интересующем месте. Неудобство этой команды - сдвиг всех последующих адресов, что затрудняет пользование листингом. Если это кому-то неудобно, можно, например, взводить одну из точек останова на самую первую команду программы, для чего внести соответствующие изменения в start32.asm и перекомпилировать его. Отладчик на экране располагается с самого верха занимая в ширину все 80 позиций и оставляя немного места снизу. При желании его можно сместить вниз задав ненулевое начальное значение старшему байту ScrDEBUG в debug.inc (1 строка). Самая верхняя строка содержит диагностические сообщения всевозможного характера. Следующая строка, начинающаяся Pre: содержит команду уже выполненную, ниже идет строка EIP: с командой которой предстоит выполнятся. В этих строках сперва идет 32 битный адрес, затем 2 байта кода операции (независимо от размера команды,даже если она однобайтовая), затем мнемоника (внимание мнемоника не переваривает префикс 67h переопределения размера адреса на 16 бит при операциях с памятью и вместо способа адресации пишет A16! хотя сама команда выполняется нормально, ну и кому нужна такая команда???)). Затем, начиная с 4-ой идут 8 строк однотипного содержания которое лучше рассматривать по столбцам.
Ну что первый столбец - регистры общего назначения ежу понятно, затем столбец наиболее употребительных флагов, следом столбец регистров сопроцессора (FPU). Регистры сопроцессора выводятся в десятичной форме, с максимальной точностью (19 десятичных разрядов мантисса) и без подавления незначащих нулей. Вообще в данном отладчике таких понятий как, удобство для пользователя, эстетичный внешний вид автором, несмотря на все усилия, не обнаружено (даже курсора нет). Впрочем, автор, как человек по натуре ленивый легко с этим смирился. Если в регистре значение неудобоваримого для FPU формата или он помечен в слове тегов как пустой то вместо числа выдается диагностическое сообщение по спецификации команды FXAM (это создаст неудобство при работе с командами MMX, но о них упомянем позже). После регистров идет столбец перечисляющий особые случаи FPU. Столбик из шести битов - маски соответствующих особых случаев (1 - запрещен). Столбик из восьми битов - слово состояния FPU - если особый случай "случился" то установившийся в 1 бит показывает с кем. 64 позиция не занята (в графике по ней проходит координатная ось, но это частности). Последняя колонка - системные регистры. Прежде всего отладки DR0 - DR3, которые можно (и нужно) модифицировать в процессе работы. Все остальные регистры модифицировать невозможно. Здесь же полная форма регистра флагов и CR0. После регистров DR0 - DR3 следует до трех букв. Первая P или L обозначают какой адрес указан в регистре на экране: физический (тот, что на шине процессора) или логический (относительно базового адреса сегмента кода в дескрипторе) на самом деле в регистре ВСЕГДА хранится значение физической памяти. Об остальных буквах будет рассказано при описании клавиш задания точек останова.

С 12 по 14 строки располагаются сперва 6 бывших сегментных регистров, а ныне селекторов сегмента с их содержимым. Они могут указывать на следующие дескрипторы:

    8h - дескриптор сегмента кодов
    10h - дескриптор сегмента данных, адреса совпадают с сегментом кодов. этот же дескриптор используется и для стека.
    18h - дескриптор сегмента данных имеющий базовый адрес 0 и совпадающий с физической памятью.

Следующие дескрипторы добавлены автором, зачем - непонятно.

    38h - дескриптор сегмента данных, базовый адрес которого совпадает с началом верхней памяти Himem
    40h - дескриптор подобный 18h, но для сегмента кодов.
    48h - дескриптор подобный 38h, но для сегмента кодов.

Дескрипторы 38h и 48h рассчитаны на полностью свободную Extended memory. Попытка сделать программу совместимой с Himem.sys потребует их модификации. В последней редакции у первых двух дескрипторов задействованы механизмы контроля пределов, которые прежде были поставлены на максимальные значения. Однако предел устанавливается с шагом 4К, а начало сегмента, от которого этот предел считается, привязано к адресу загрузки задачи в памяти, который Dos выравнивает на 16 байтную границу. В результате контроль предела не удается выставить точно на границу FFFFFFFFh - 00000000h и в результате будет запрещен доступ в небольшую область в конце памяти, где расположен BIOS (его, правда никто не использует, т.к. предпочитают его копию в конце первого мегабайта). Заставить Dos загружать задачу с 4К границы автору не удалось. По той же причине не используется специальный дескриптор для стека (с перевернутым пределом). Правда защита не распространяется на область дескрипторов и векторов прерываний и при ошибке в программе их можно случайно затереть, что приводит к зависанию или перезагрузке системы не давая возможности локализовать ошибку. Однако прикрыть эти области механизмом защиты довольно сложно т.к. программа чужая, хотя и возможно. У кого будет на то желание - дорабатывайте по своему вкусу. Стек кстати небольшой - 4К байт. Кому мало добавьте TSTAK в начале start32.asm. Вообще дескрипторы создавать очень легко. Добавляйте строку с типом desc (перед строкой с меткой idt32) и настраивайте поля, но главное не забудьте увеличить на 8 первый байт слова gdt32a (размер дескрипторной таблицы). Номер нового дескриптора так же будет на 8 больше предыдущего. Пример применения - создается массив данных и равный ему дескриптор (размер удобно выбирать кратный 4К байт - шагу задания предела). В этом случае при обращении к массиву через его дескриптор будут автоматически контролироваться его размеры и нет необходимости в применении команды BOUND.

При обращении к массиву через созданный для него дескриптор, в случае нарушения его границ будет генерироваться особый случай General Protection Violation.

В этих же строках располагаются значения некоторых переменных самого Dos Extender-а, которые могут быть полезны при программировании. Вот они:

    LoBase - Начальный адрес свободной нижней памяти. Т.е. до 1 Мегабайта
    LoEnd - Ее же конечный адрес. Размер - их разница - не приводится.
    HiBase - Начальный адрес верхней памяти (вся она, разумеется, свободна).
    HiEnd - Ее же конечный адрес.
    HiSize - Ее же размер.

Адреса эти - логические, т.е. относительно сегмента кодов. Для получения из них физического адреса необходимо прибавить к ним базовый адрес сегмента, который представлен на экране как Code32 и соответствует внутренней переменной _code32a. Если кто захочет модифицировать сам Dos Extender должен обратить внимание на одну особенность. Для упрощения программы и пользуясь тем, что ее размер со всеми потрохами не превышает 64К еще Tran для задания некоторых 32 битных адресов использовал только младшие 16 бит адреса, пользуясь конструкцией [small address]. Автор так и не выяснил, как в ассемблере взять СТАРШИЕ 16 бит 32 битного адреса, но до размера больше 64К далеко и эта особенность вряд ли кому помешает. Тем более, что 64К не должна превысить только часть start32.asm, а к части пользователя, которая компилируется отдельно и компонуется со start32.obj это никак не относится. Она может быть любого размера. Следующая колонка опять посвящена FPU. Из регистра управления FPU даны

    Prec. Contr - точность мантиссы 32, 53 или максимальная - 64 бита,
    Round Contr - контроль округления:
    Nea - к ближайшему,
    - < - к минус бесконечности (вниз),
    > + - к плюс бесконечности (вверх),
    >0< - к нулю.


В строке C0C1C2C3 представлены 4 бита слова состояния FPU - SW, которые переносятся командами FSTSW AX и SAHF в регистр EFLAGS для управления переходами В последней почти пустой колонке последовательность цифр от 0 до B шестнадцатеричная позиция символов просмотра памяти идущих под ними. Две последних информационных строки отображают (независимо друг от друга) два участка памяти по 12 байт каждый в байтовой и символьной форме. Адрес памяти может быть логическим или физическим подобно адресам в регистрах отладки. Лучше была бы адресация относительно выбранного дескриптора, но автор ленив, а подпрограмма для регистров отладки уже была готова. Если есть желание переделайте (хотя признаться автор уже сейчас в своей программе ни черта понять не может, так что не завидую).Если ваш процессор поддерживает Time Stamp Counter (TSC) то можно добавить его содержимое к выводимой на экран информации. Это удобное средство для оценки оптимальности кода для каких-либо фрагментов программы. Кто незнаком с ним поясняю: в процессорах начиная с Pentium добавлен 64 разрядный счетчик тактов процессора, который можно считывать и записывать. По разнице значений можно выяснить сколько процессорных тактов требует тот или иной фрагмент.

Это просто реализовать добавлением в начало и конец интересующего фрагмента следующих кодов:

Code:
XOR EAX,EAX
XOR EDX,EDX
MOV ECX,10h ;код обращения к TSC
WRMSR ;обнуление счетчика
... ;фрагмент программы
RDTSC ;считывание счетчика, старшие биты в EDX, младшие в EAX


ВНИМАНИЕ! Команда RDTSC введена в процессоры с шестого поколения - Pentium Pro, Pentium II, AMD K6 и в TASM5.0 ее нет, она поддерживается WASM. При использовании процессоров пятого поколения или TASM ее заменяют две команды

Code:
MOV ECX,10h ;код обращения к TSC
RDMSR ;чтение счетчика


хотя для TASM на процессорах шестого поколения можно использовать конструкцию:

Code:
dw 310Fh ;код команды RDTSC


для более благовидного текста программы можно объявить эту команду макросом:

Code:
RDTSC macro
dw 310Fh
endm


и в тексте использовать нормальную мнемонику. К сожалению, этот метод годится только для безоперандных команд, а то достаточно было бы составить include с макросами отсутствующих в компиляторе команд и подключать его по необходимости что решило бы проблему старых версий компиляторов для DOS.

Немного тактов добавиться на собственно команды WRMSR, RDMSR или RDTSC. Но если встроить вывод значения этого счетчика в отладчик, то придется учитывать такты, затрачиваемые на вызов самого отладчика и вычитывать их из результата, а число этих тактов зависит от типа процессора. При пошаговой отладке TSC бесполезен, но удобен при отладке по точкам останова, необходимо лишь обнулять его при выходе из отладчика. Если фрагмент содержит операции с памятью, то значение TSC может немного меняться случайным образом. Дело в том, что для операций чтения из памяти количество требуемых тактов будет зависеть от моментов регенерации памяти, а так же от попаданий в кеш. Операции записи современные чипсеты довольно глубоко буферизуют, но при переполнении буфера и они станут давать непостоянный результат. Влияние кеша можно исключить, перед сбросом TSC объявляя кеш недостоверным командой WBINVD. Но для анализа глубоких циклов, при оценке только одного прохода результат будет недостоверным, т.к. время выполнения при отсутствии попаданий в кеш будет совершенно несоответствовать реальной ситуации. Циклы необходимо анализировать, создавая ситуацию, чтобы все коды находились в кеш памяти. Еще одна интересная команда оптимизации введена в процессорах K6-2, почему-то в составе инструкций 3DNow. Команда PREFETCH addr вызывает загрузку в кеш данных первого уровня 32 байтной строки указываемой addr, что позволяет программисту заблаговременно переместить данные в кеш во время выполнения других операций. В последующих поколениях процессоров AMD предполагается несколько отличная команда PREFETCHW для данных которым предстоит модификация. Пока же обе команды выполняются идентично. Правда, аналогичного эффекта можно добиться чтением в любой незанятый регистр общего назначения, если таковой окажется в устраивающем программу месте, зато это можно делать на любом типе процессора.

ФУНКЦИОНАЛЬНЫЕ КЛАВИШИ

F1 - Single Step. Выполнение одной команды на которую указывает EIP.Позволяет входить в подпрограммы, но обходит команды INT всех видов, действуя подобно F2.

F2 - Ведет себя подобно F1, но натыкаясь на вызов подпрограммы не входит в нее, а ждет когда она кончит. Заставляет кончать команду LOOP и ее разновидности, а так же всевозможные команды с префиксами повторения (REP, REPE/NE) . Для ее работы зарезервирован регистр отладки DR3 и им лучше не пользоваться при пошаговой отладке. G - Go - отправляет программу на выполнение с текущего адреса в расчете на точки останова или нормальное выполнение. Можно пользоваться DR3.

U - User Screen. Объяснять, что это такое надеюсь не надо, но в графическом режиме не работает. ESC - Выход из программы в любом месте (включая графику).

0, 1, 2, 3[b] - Установка точек останова соответствующих регистров DR. Нажав клавишу выбранного регистра набираете адрес, который заканчиваете нажатием L или Enter, если он логический или P если он физический. Следом, от вас ожидается нажатие C или Enter, если контрольная точка по команде, R если по данным в режиме запись/считывание и W в режиме только запись. В случае выбора контрольной точки по данным необходимо еще задать размер данных, нажав B или Enter в случае указания однобайтового поля, W слова и D двойного слова. Отсутствие курсора создает некоторое неудобство. В крайнем случае, можно лишний раз нажать Enter - вне режима установки контрольных точек он не производит никаких действий. Для снятия точки останова достаточно вместо адреса нажать Enter (но DR7 изменится только после хоть одной команды).

Для использования добавленных у Pentium точек останова по обращению к портам ввода-вывода необходимо указать обязательно ФИЗИЧЕСКИЙ адрес порта и нажать I (если для адреса ввести L то последующее I не будет восприниматься). Размерность данных указывать не нужно, она автоматически устанавливается байтовой, хотя этот момент в оригинальной документации INTEL почему-то не отражен, а по документации AMD она может быть и WORD и DWORD. Чтобы точки останова по обращению к IO портам работали, необходимо взвести в 1 бит DE в регистре CR4. Сделать это можно так:

Code:
MOV EAX,CR4
OR AL,08h ;3-й бит регистра CR4
MOV CR4,EAX


разместив эту последовательность либо в пользовательском модуле, либо в start32.asm перед командой jmp _main. Автор не стал ее добавлять из-за 486 процессоров, у которых обращение к CR4 воспринимается как Invalid Opcode.

Наиболее часто используемая простейшая точка останова, втыкаемая в текст программы, где попало команда INT 1. Автор пользуется ей для задания самой первой точки останова в начале программы. Но эта команда создает неудобства при пользовании листингом, все время сдвигаются адреса. Кстати, аналогичная по функциям INT 3, но использующая другой Interrupt, игнорируется и задавать ее хоть и не вредно, но бесполезно.

Внимание! Установленные точки останова DR0-3 замедляют у некоторых типов процессоров скорость выполнения программ и оценка производительности в режиме отладки может быть неверной. Сообщение об останове по INT 1 в случае, когда эта точка не задавалась, свидетельствует о проблемах в отладчике. Это сообщение может выдаваться в случаях, когда отладчик не смог определить, по какому вектору произошло прерывание.

[b]M, N
- Просмотр содержимого памяти. M - верхняя строка, N - нижняя. Адрес набирается так же как для регистров отладки, с указанием логический он или физический. Чтобы не набирать одни и те же адреса при каждом старте, их можно установить как начальные значения переменных SysRegM и SysRegN. Необходимо так же установить и биты 2 и 3 ModeAddrDeb для M и N соответственно (0 - логический адрес,1 - физический) в debug.inc, но при каждом изменении придется перекомпилировать start32.asm. Если изменения требуются очень часто, эти переменные можно объявить external и перенести в пользовательский модуль. Для точек останова эти методы не очень подходят т.к. кроме адресов необходимо инициализировать регистр управления отладкой DR7.

Left,Right[b] - Тоже участвуют в просмотре памяти уменьшая или увеличивая на 1 счетчик адреса строки, на которую указывает значок - направленная вниз стрелочка. PgUp,PgDn - Тоже самое, но счетчик адреса меняется на 12

[b]Up,Dn
- Перемещают указатель на строку M или N для их сдвига клавишами направления при просмотре памяти

[b]X, F[b] - См. ниже.

Остальные - Ни черта не делают.

Теперь о процессорах, на которых написано слово из трех букв (автор имеет ввиду MMX). Для отображения регистров FPU как MMX выделена самая большая буква X, какая только нашлась на клавиатуре. Возврат к их отображению как FPU происходит клавишей F. При пошаговой отладке переключение происходит автоматически по типу исполняемых команд, но при использовании точек останова предыдущий контекст может быть ошибочным и потребуется принудительное переключение. Надо заметить, что переходить к MMX представлению регистров можно даже на процессорах не поддерживающих этот набор команд, (весь отладчик создан на AMD 5x86, т.е. фактически 486 процессоре) что позволяет например, просматривать мантиссу чисел с плавающей запятой в шестнадцатеричном формате (номера MM и ST регистров могут при этом не совпадать, но это будут одни и те же регистры). Нумерация MMX регистров может идти не по порядку начиная с нуля, а с произвольного значения от 0 до 7. Дело в том, что у MMX представления есть особенность. MMX регистры не имеют стековой организации подобно FPU и номер регистра всегда АБСОЛЮТНЫЙ, тогда как у FPU регистров он считается относительно 3-разрядного указателя вершины стека. Номера регистров совпадают только при указателе стека равном нулю. Очищение регистров и обнуление указателя стека считается желательным (но вовсе не обязательным) условием перехода от FPU к MMX командам, впрочем, первая же MMX команда сама сбросит в 0 указатель стека. Просто соблюдение этого правила делает программу более логичной и облегчает контроль ошибок, и если при попадании на MMX команду нумерация регистров идет не с нуля, значит стек не нулевой и возможно в программе есть ошибка. TASM 5.0 эти команды не поддерживает, и следующих версий его для Dos уже не будет (а MASM вообще отказывается компилировать для защищенного режима Dos). Тем, кому необходимо использовать команды MMX, а так же добавленные у шестого поколения INTEL (только) процессоров команды условной передачи данных CMOV и FCMOV, можно воспользоваться ассемблером WASM 11.0 от Watcom C++ 11.0, но только для модуля пользователя, выкинув из start32.inc ненужную этому компилятору команду jumps, а взамен указав тип процессора .686 Системный же модуль start32.asm им компилировать нельзя, WASM от него вылетает в фатальную ошибку, для этого пользуйтесь традиционным TASM. Последующая компоновка должна производиться с помощью TLINK, как и при обычной работе. Кстати, добиться листинга от WASM автору так и не удалось, правда, особой нужды в этом не возникало. Для добавленных у INTEL и AMD разных наборов команд 3D графики - компиляторов под DOS вроде бы нет и, кажется уже не будет. Конечно, можно воспользоваться конструкциями DB, но это уже даже не ассемблер, а автокоды. Однако если подобные команды и встретятся и процессор их поддерживает - работать они будут, только вместо мнемоники в отладчике будет пустое место (но возможна и неверная мнемоника). Под набор команд 3DNow процессоров AMD и Cyrix у данной версии дизассемблера выдается мнемоника 3DNow с указанием операндов. Код операции определяется у этих команд ПОСЛЕ указания операндов и формирование мнемоники в дизассемблере несколько хлопотно. Возможно добавление ее впоследствии, но после операндов. Поддерживающий команды современных процессоров NetWide Assembler (NASM) автору задействовать не удалось, из-за множества несовместимостей с TASM. Возможно (но автором не проверено) компилирование пользовательского модуля современными ассемблерами работающими под Windows, что должно позволить использование любых добавляемых команд, но требуемая при каждом изменении программы перезагрузка между Dos и Windows способна вывести из себя гранитного истукана, а не то, что программиста из плоти и крови, разве что де


30 Jul 2007 10:57
Profile
Fanat

Joined: 30 Jul 2007 10:31
Posts: 51
Reply with quote
Внимание! Если вас угораздит последовать уговорам автора,
- Помните! Эксперименты описываемые ниже, чрезвычайно опасны
и их рекомендуется проводить сперва на собаках...


Quote:
А НЕ НАПИСАТЬ ЛИ НАМ СОБСТВЕННЫЙ ДРАЙВЕР HARD ДИСКА...

Название, так же, подразумевает такие хорошие веши как PCI IDE Bus Master, всевозможные UDMA, и защищенный 32-битный режим.

Много горьких слов сказано про INT 13h появившийся на свет более 20 лет назад в 16-битную эпоху, и с тех пор натягиваемый на растущие как на дрожжах объемы дисковой памяти, как будто он сделан из сырой резины. Изначально заложеное в него ограничение на 1024 допустимых цилиндра породило первый барьер в 528М дисковой памяти. Выворачиваться пришлось разработчикам интерфейса, которые разродились LBA трансляцией адреса. Главное ее достижение, это линейная 28-битная адресация секторов, делающая ненужными такие понятия как Сектор, Головка, Цилиндр. Ими теперь занимается процессор Hard диска. Однако INT 13h прочно ставший стандартом BIOS требовал именно сектора, головки и цилиндры в качестве передаваемых параметров, посему далее прогресс в этой области пошел не только боком, но и раком, в каковом виде он до сих пор и находится.

LBA трансляция для преодоления ограничения INT 13h в 1024 цилиндра буквально пересчитывает цилиндры в головки с целью уменьшения количества первых за счет увеличения количества последних. Однако решение было не лучшим, так как было временным и на размере 8.4G пересчетные возможности LBA оказались исчерпанными, а диски тем временем перевалили за десятки гигабайт. Собственно ATA стандарт позволяет адресовать 136.9G на каждый диск. Более того два бита в адресе не задействованы, что позволит учетверить, а в случае передачи бита LBA/CHS на адресацию и увосьмерить эту цифру. Разработчики вероятно зарезервировали 2 бита из-за неопределенности, что потребует стандарт в будущем - увеличивать адреса или количество устройств (их сейчас два на канал). Собственно решение уже очевидно - адрес. Пока же в INT 13h добавили несколько новых функций, наконец, позволяющих работать с дисками более 8.4G. Правда вызов их, на взгляд автора, организован довольно дурацки, но главный недостаток не в этом.

Компьютеры давно стали 32-битными. Это значит, что возможна прямая работа с оперативной памятью до 4G. В 16-битном режиме допускалось только 64К - больше только с переключением сегментов, но не более 1М. INT 13h будучи, как и почти весь BIOS, 16-битным, может работать лишь в пределах первого мегабайта и его не колышет, что у вас этих мегабайт, к примеру, сотни. Это значит, что вам для передачи данных выше первого мегабайта потребуются повторные, причем совершенно неоправданные, передачи память - память. 32-битной альтернативы INT 13h в BIOS, на сегодняшний день нет. А между тем, в режимах PIO и PCI IDE Bus Master адрес можно, а иногда и нужно указывать 32-битным. Возможно и использование старого DMA контроллера, но он застыл в развитии на уровне PC AT и адресом более 16М разродиться тоже не способен и его присуствие в архитектуре, скорее всего лишь дань совместимости. Конечно, если вы работаете в любой современной 32-битной ОС, то вас этот момент не затрагивает. Все они снабжаются полноценными 32-битными драйверами. Однако наряду с достоинствами, эти ОС имеют и недостатки, в частности невозможность монополизации ресурсов процессора и памяти для решения только одной задачи. Подробнее этот момент расписан в статье "Отрицательные стороны многозадачности ОС" которую можно найти на страничке автора:
http://users.caucasus.net/dosextender

Если вы пришли к выводу, что для вашей задачи необходима однозадачная среда, то остается работа только из под Dos Extender-а, каковой из-за отсуствия дисковых драйверов общего назначения, вынужден использовать INT 13h со всеми его недостатками. За основу, в данном случае, взят авторский Dos Extender, который можно найти на вышеупомянутой страничке, благо он в исходных текстах и с отладчиком. К тому же, у него запрещено страничное преобразование, которое резко усложнит драйвер для DMA режимов (Не возмущайтесь, если заметите в основе его Dos Extender от 1993г. некоего Tran'a. Его авторство многократно упомянуо, более того, приведен и оригинальный его вариант). Впрочем, своя рука владыка, так что Dos Extender выбирайте какой вам больше нравится.

Сразу надо определить - нужен ли драйвер вообще. Во-первых, многим задачам скорость дисковых операций безразлична, они могут составлять лишь малую толику от общих затрат времени, так чего огород городить. Во-вторых, файловая система ДОС работает только через INT 13h и ваша задача, с собственным драйвером, должна работать минуя файловую систему - непосредственно с диском на уровне физического доступа к секторам, а это может потребовать создание собственного раздела с какой-либо разбивкой заменяющей файловую систему, пусть даже на примитивном уровне, но удовлетворяющем нужды задачи.

Предположим, вы пришли к выводу, что задача действительно нуждается в драйвере. Но в каком? Существующие протоколы обмена позволяют:

PIO - программировать попроще, но занят процессор, зато если ваш Dos Extender использует страничное преобразование, за это отдувается процессор. Однако, скорость обмена выше 16M/s вам не светит, хотя не теряется время на очистку кеш памяти при обмене - все данные и так достоверны.

PCI IDE Bus Master - программируется посложнее, но позволяет процессору во время дисковых операций, делать еще что-то хорошее. Если контроллер и сам Hard диск поддерживают режимы UDMA33, 66 или 100 то и скорость обмена вы получите соответствующую. Правда завершать операцию чтения (а операцию записи наоборот предварять) должна команда полной очистки кеша WBINVD, т.к. обмен данными происходит непосредственно с памятью, которая может не совпадать с содержимым кеша с Обратной записью (кеш первого уровня всегда такой, кроме 486 процессоров). Процедура это достаточно долгая и не портит общую картинку только в случае передачи достаточно больших объемов данных. Если же вас угораздило работать в режиме страничного преобразования - вот тут-то оно кровь вам и выпьет. Извольте пересчитать все адреса из линейных в физические, впрочем, этого нехорошего момента мы касаться не будем - у автора на страничное преобразование аллергия.

Предположим, что более привлекательным сочтен Bus Master протокол и ваш Hard диск поддерживает UDMA, тем более что 100, 66 или 33 явно больше чем 16. Остается решить, должен ли процессор во время дисковых операций еще что-то делать. Int 13h этого принципиально не позволяет. Он монопольно занимает процессорное время, часть которого составляет пустое ожидание. Драйвер с аналогичным поведением будет несомненно проще, поэтому на нем и остановимся. Сделать его посложнее, с параллельной работой, можно, но ой-ли нужно! Например для задачи поиска некоего контекста на диске, без использования параллельной работы результаты таковы: чтение с диска в память и последующий поиск в памяти, на 10 - 15% длятся дольше чем просто чтение с диска, безо всякого поиска, т.е. выигрыш за счет параллельной работы и составит эти несчастные проценты. Да не стоят они того!!! Абсолютные же показатели таковы: подобное сканирование диска 10G заняло около 15 минут в режиме UDMA33, дешевый процессор AMD K6-2/350, чипсет VIA MVP3, 128M памяти. Средняя скорость передачи 13M/s. Для сравнения, там же DiskEditor аналогичный контекст жевал примерно час, в пределах 1G !!! (на большее терпения не хватило). Вообще, премущество даже не в скорости, а в том, что имея исходный текст, контекст поиска можно сделать составным и вообще сколь угодно сложным.

Самый тяжелый момент параллельной работы - синхронизация процессов. Параллелить несколько дисковых операций, например при наличии двух Hard дисков, не рекомендуется, хотя наличие двух каналов у контроллера, это позволяет. Затраты на арбитраж PCI шины могут "съесть" скорость (исключение может составить довольно экзотичная задача переписи данных с диска подключенного к одному контроллеру на диск подключенный к другому. В этом случае выборка данных (не занимающая шину) диска с которого производиться чтение, может производиться одновременно с передачей данных (от предыдущего чтения) на записываемый диск. Вторая фаза - передача считанных данных будет производиться одновременно с выполнением вторым диском операции записи. Кстати, для подобной задачи не нужно объявлять недостоверным кеш. Данные не используются процессором, а контроллеры оперируют непосредственно с памятью).

Для осуществления параллельной работы скорее всего потребуется создание небольшой управляющей надстройки, своеобразного "супервизора" которая и будет распределять задания процессору и дисковому контроллеру, отслеживать их очередность и завершение, но это уже выходит за рамки драйвера. Дисковые операции придется ставить на контроль таймеру во избежание зависания при ошибочных или сбойных ситуациях (прерывания ведь можно и не дождаться).

Для тех кому параллельная работа не нужна, спецификации начиная с ATA-4 позволяют уменьшать затраты времени на ожидание готовности данных к передаче используя набор команд с поддержкой очередей (Queue). Последующую команду можно выставлять еще до того как отработает предыдущая. Однако программирование с их использованием чересчур усложнилось и некоторые производители предпочли путь повышениея эффективности обычных команд, т.е. при интенсивном обращении к длинным цепочкам секторов, последующие данные начинают подготавливатся заранее, еще до поступления на них запроса (вообще-то, документального подтверждения этому у автора нет, но временные замеры операций наводят на подобные мысли). В общем, диск которым располагает автор (WD 10G), эти команды не поддерживает.

Однако, немного коснемся пресловутого PCI IDE Bus Master. С чем его едят? Познакомиться с ним можно по первоисточнику - стандарту SFF-8038i. PCI шина кроме прочих своих обязанностей, стала 32-битной альтернативой контроллеру DMA, который создавался для 16-разрядной ISA шины и поэтому исходно мог передавать за один присест до 64К данных в пределах 1 мегабайта доступных ранним PC XT. С появлением 286 PC AT адресация расширилась до 16М за счет увеличения шины данных до 24 разрядов, но порции остались прежними. Режим Bus Master для устройств PCI как раз и выполняет задачу передачи данных в 32-разрядном адресном пространстве НЕ ЗАНИМАЯ ПРОЦЕССОР. Порции разовой передачи в принципе не ограничены, но могут иметь, определяемый контроллером устройства, предел. Для IDE контроллера, разовая передача осталась в принципе те же 64К байт, однако общая передача может составить 512M без дополнительного вмешательства, контроллер все сделает за вас. На архитектуру контроллера вероятно наложило свой дурной отпечаток, пресловутое страничное преобразование. В общем, он спроектирован под задачу - раскидать различные сектора с диска по РАЗНЫМ фрагментам памяти. Вроде бы, с точки зрения обычной задачи намерение довольно идиотское, но если исходить из структуры FAT (практически во всех ОС файлы хранятся не сплошным куском, а раскиданы по диску кластерами) или назначения SWAP-файла (см.Виртуальная память), то все становится на свои места. Работает это так. В памяти создается специальная таблица неких Дескрипторов (Physical Region Descriptor или PRD). Каждый дескриптор это 2 двухсловных (DWORD) элемента, где первый задает начальный адрес региона передачи, а второй счетчик байтов. Счетчик байтов не должен превышать 64К. Обший размер таблицы тоже не должен превышать 64К, т.е. дескрипторов должно быть не больше 8К, что и дает максимальный размер одной операции 512M. Признаком последнего Дескриптора таблицы является 1 в старшем (31-ом) бите счетчика байтов. Еще одно ограничение. Таблица, мало того должна быть выровнена в памяти на 4-х байтную границу, но и не должна пересекать 64К границу физической памяти. Практическое использование могут иметь таблицы из максимум двух Дескрипторов. Дело в том, что хоть контроллер и позволяет передавать 512M, но сами диски имеют ограничение одной операции - максимум 256 секторов, что дает 128K, а для их передачи достаточно двух Дескрипторов. Контроллер программируется через три регистра, а именно Команд, Состояния и Указателя на таблицу Дескрипторов. Регистры первого и второго контроллеров раздельные, что позволяет им работать независимо, а при желании и одновременно. Базовый адрес регистров получить довольно хлопотно. Необходимо вызывать функции конфигурации PCI устройств из BIOS32 Directory Service. Хоть и не предполагалось, но подпрограмма запроса этого адреса все же сделана и включена в драйвер. Поскольку для каждого компьютера это достаточно определить раз в жизни, впоследствии в программах для себя этот фрагмент можно опустить и задавать адрес как константу.

Предположим, базовый адрес у нас E000h.

Регистры распределятся так:

E000h - Регистр Команд. Размер BYTE.

    Бит 3 - Направление передачи. Для чтения диска - 1, для записи - 0.
    Бит 0 - Запись в него 1 вызывает старт операции передачи. После завершения операции его необходимо сбросить.
    Остальные биты не используются и в них должны быть 0.

E002h - Регистр Состояния. Размер BYTE.

    Бит 7 - Информационный. 0 в нем показывает, что оба контроллера способны работать одновременно.
    Бит 6 - Должен показывать, что диск Slave первого контроллера способен работать в DMA режимах. Взводиться должен, судя по всему, программой инициализации. Толку от него нет. Какой из ваших дисков поддерживает DMA вы и без него знаете. (надо заметить что поддерживаться должен, как минимум, режим Multiword DMA Mode 0 или более шустрые разновидности Mode 1, Mode 2, UDMA33, UDMA66). Можно и взвести для порядку.
    Бит 5 - То же, что Бит 6, но для диска Master первого контроллера.
    Бит 2 - Interrupt. Показывает, что диск выставил сигнал прерывания. Это сигнал КОНТРОЛЛЕРУ, что диск приготовился к обмену, а уж после обмена, контроллер выставит, уже свое прерывание процессору. Прерывание от диска попадает сразу на процессор только в PIO режимах. После выполнения операции его необходимо обнулить записав в него 1 (а не 0 )
    Бит 1 - Error. Ну, что это такое - ежу понятно. Для очистки этого бита необходимо записать в него 1, подобно биту 2.
    Бит 0 - Bus Master active. Смысл тоже ясен. Взводиться сам, как только взведен стартовый бит в командном регистре. Сбрасывается тоже сам, как только завершены все передачи заданые в таблице или сброшен стартовый бит. Если вы не хотите работать по прерываниям, можете анализировать этот бит, но параллельная работа в этом случае исключается. Замечена странная вешь. Прерывание означающее конец операции происходит несколько позже, чем сбрасывается этот бит и немалое время задержки пропорционально количеству передаваемых байт.
    Остальные биты не используются и в них должны быть 0.

E004h - Регистр Указателя на таблицу Дескрипторов (PRDT). Размер DWORD. Младшие два бита должны содержать 0.

Для Второго контроллера все аналогично:

    E008h - Регистр Команд.
    E00Ah - Регистр Состояния.
    E00Ch - Регистр Указателя на таблицу Дескрипторов (PRDT).

Нельзя не заметить, насколько сложной должна быть внутренняя структура такого контроллера. Это фактически должен быть специализированный процессор, хотя для выполнения этой же задачи (без бестолковых таблиц и Дескрипторов) вполне достаточно простого конечного автомата.

Раз уж взялись рассматривать программное назначение регистров, то неплохо бы за компанию, вспомнить и функции регистров самого IDE контроллера, которые управляют непосредственно диском, в то время как IDE Bus Master только передачей данных. Эти регистры, так же разбиты на две группы - каждая своему контроллеру. Адреса 1F0h - 1F7h для первого контроллера, 170h - 177h для второго. Надо сказать, что функции IDE контроллера расписаны в ATA стандартах, и для задействования UDMA режимов необходимо пользоваться хотя бы версией ATA-4, хотя есть и ATA-5. Обоими стандартами можно разжиться на страничке:
http://www.halyava.ru/document/ind_hard.htm

Расширения этих стандартов ATAPI в данном случае интереса не представляют и применяются в устройствах где стандартного набора регистров IDE контроллера не хватает и введено расширение ATA Packed Interface, например, для CD-ROM.

1F0h - R/W. Данные. Используется только в PIO режимах. Размер WORD.

1F1h - RO. Error. В случае ошибочных ситуаций, содержит тип ошибки. BYTE.

1F1h - WO. Features register. Передает дополнительные параметры некоторых комманд. Размер BYTE.

1F2h - RW. Счетчик секторов. При нулевом значении регистра, передается возможный максимум - 256 секторов. Размер BYTE.

1F3h - RW. Номер сектора. Нулевое значение регистра запрещено. Сектора считаются с 1. Допустимо 1 - 256. Размер BYTE.

1F4h - RW. Цилиндр. Младший байт.

1F5h - RW. Цилиндр. Старший байт. Всего цилиндров допустимо 0 - 65535.

1F6h - RW. Устройство/Головка. Размер BYTE.

    0 - 3 биты задают номер головки 0 - 15.
    4 бит - задает устройство Master/Slave - 0/1.
    6 бит - LBA трансляция. Для CHS должен быть 0.
    7 и 5 биты - не используются и должны быть 1.

1F7h - RO. Status register. Размер BYTE.

[/list]7 бит - Busy т.е. Занято. Очень важный бит (может также использоваться в общественных сортирах). Пока этот бит 1, устройство выполняет операцию и ни черта не видит и не слышит. Посему, остальные биты этого регистра в это время недостоверны.[/list]
    6 бит - Device Ready. Усегда Готов.
[/list]5 бит - Device Fault. Прямая противоположность предыдущенго бита. Если этот бит взводиться, то дальнейшие действия могут быть следующими: Device отправляется либо в мусорный ящик, либо в мастерскую. Первое предпочтительнее (ближе, а результат тот же).[/list]
    4 бит - Device Seek Complete. Используется только в тестах.
[/list]3 бит - Data Request. Фактически это сигнал запроса прерывания, т.е. устройство готово к передаче данных. В PIO режимах попадает сразу на процессор, а в IDE Bus Master на контроллер, а уж он после передачи выставляет прерывание процессору.[/list]
    2 бит - Corrected Data. Сообщает, что считанные данные подверглись исправлению от ошибок, однако достоверны. Может быть задействован в задачах повышенной важности, т.к. возможности исправления не абсолютны, хотя и достаточно эффективны. Может также сигнализировать о приближении момента взведения 5 бита, со всеми вытекающими последствиями. Правда S.M.A.R.T это делает лучше.
    1 бит - Index. Атавизм (например, хвост у человека или бесхвостая обезьяна).
    0 бит - Error. Тип ошибки можно посмотреть в одноименном регистре.

ВНИМАНИЕ! Чтение этого регистра, является одновременно сигналом подтверждения прерывания, который необходимо подавать при завершении обработки этого прерывания. Для того, чтобы не нарушить ход операции, этот регистр дублируется по адресу 3F7h. Это т.н. Alternate Status register. Его чтение можно производить в произвольный момент времени, подтверждения прерывания это не вызывает.

1F7h - WO. Command register. Размер BYTE.
Команд в общем-то чортова пропасть, однако сейчас интерес представляют следующие:

    C8h - Read DMA with retries
    CAh - Write DMA with retries

Понятие with retries и without retries относятся к сбойным ситуациям, и подразумевают наличие или отсуствие повторных попыток успешно завершить операцию. Смысл примерно такой же, как и бита Corrected Data. Обычно используются команды with retries, тем более что команды

    C9h - Read DMA without retries
    CBh - Write DMA without retries

и им подобные, в стандарте ATA-4 уже исключены как анахронизм.

Итак, какова последовательность действий выполнения, например, операции чтения. Для режимов Bus Master, ее осуществляют два различных устройства, собственно IDE контроллер управляющий действиями Hard диска, и IDE Bus Master контроллер, занимающийся передачей данных.

1. Проверяются всевозможные регистры состояний на предмет того, что бы все было свободно для выполнения новой операции. У IDE контроллера проверять нужно ТОЛЬКО Альтернативный регистр состояния 3F7h/(377h), чтоб не выдать сигнал подтверждения прерывания до окончания предыдущей операции.

2. Инициализируются регистры IDE контроллера задающие цилиндры/головки/сектора и количество секторов предназначеных к передаче. Затем, можно сразу же выдать и код команды, что приведет к немедленному началу операции, и c задержкой 400ns взведет бит Busy.

3. Необходимо подготовить к работе IDE Bus Master. В ФИЗИЧЕСКОЙ памяти готовиться Таблица PRDT. На этот момент можно запретить кеш регистром CR0, это будет быстрее чем команда WBINVD. Адрес таблицы заносится в регистр Указателя на таблицу Дескрипторов E004h/(E00Ch), хотя он может заноситься туда однократно при инициализации драйвера.

4. Устанавливается бит направления в регистре команд E000h/(E008h) и одновременно взводится стартовый бит, что начинает операцию передачи. В этот момент взводится бит Active.

Происходит все следующим образом: Hard диск получив команду, позиционирует головки на нужный цилиндр, а затем списывает данные во внутренний буфер. Покончив с этим, он выставляет IDE Bus Master контроллеру, прерывание, мол, у меня все готово. Получив такой сигнал, IDE Bus Master контроллер начинает операцию передачи. В настоящий момент не выяснено, что происходит дальше, ибо бит Active через некоторое время сбрасывается, что должно свидетельствовать об окончании передачи, но прерывание процессору выставляется с задержкой, пропорциональной количеству передаваемых байт. Для работы драйвера, вообще-то, это безразлично, но непонятно, а следовательно неприятно. Обработчик прерывания должен выполнить несколько подтверждений прерываний и сбросить некоторые биты.

Собственно драйвер состоит из трех частей.

    Инициализация всего и вся.
    Подпрограмма работы с диском на физическом уровне.
    Подпрограмма работы на логическом уровне, в пределах выбраного раздела.

Ну, по порядку.

Простейшая инициализация предполагала, только перехват прерываний 14 и 15, и проверку готовности устройств. Базовый адрес Bus Master контроллера и количество секторов на диске предполагалось вносить как константы, как величины постоянные для конкретной машины. Впоследствии встала проблема мобильности программы, и в добавились подпрограммы автоматического определения этих значений (если работать только на конкретной машине, для простоты, можно вернуться к константам). Вот они:

    CommandIdeBusMast dw ? ;See PCI Configuration space
    StatusIdeBusMast dw ? ;CommandIdeBusMast + 2
    PRDTIdeBusMast dw ? ;CommandIdeBusMast + 4
    CommandIdeBusMast1 dw ? ;CommandIdeBusMast + 8
    StatusIdeBusMast1 dw ? ;CommandIdeBusMast + 10
    PRDTIdeBusMast1 dw ? ;CommandIdeBusMast + 12

    CapasityDrive0 dd ? ;Words 60-61 of IDENTIFY DEVICE
    CapasityDrive1 dd ? ;0 - if device not present
    CapasityDrive2 dd ? ;Set in InitDrvIDE
    CapasityDrive3 dd ?


Адрес Bus Master определяется через BIOS32 Directory Service, по методике описаной в SFF-8038i. Описание BIOS32 имеется только в PostScript и его можно только распечатать, и только на принтере с поддержкой этого формата. Возможно стандарты будут выложены автором на своей страничке т.к. собирать их по halyav'е хлопотно, а включать в комплект драйвера - лишние 160K архива.

Подробно вызова этих функций касаться не будем, единственно что желательно упомянуть, это особенности дальних вызовов этих функций. Они требуют загрузки в DS дескриптора адресующего ВСЮ память от 0 до 4G. В данном Dos Extender'е такой дескриптор 18h. Посему вызов (через память) приходится проводить по ES, равному текущему дескриптору 10h.

Возникает еще один вопрос инициализации. Кто определяет скорость? Например реальний средний трансфер 13M/s показываемый UDMA33 вызывает подозрение в некоем надувательстве или некорректной установке скорости. Конечно из среднего трансфера нужно выкинуть затраты времени на позиционирование головок, но замеры скорости от момента поступления прерывания контроллеру, с чего начинается собственно момент передачи данных, до прерывания процессору - на чем он собственно заканчивается, показывают пиковое значение всего лишь 17M/s (а может это и есть пресловутое 16.6), что все равно гораздо ниже 33. В чем там дело, объяснить затруднительно - нет литературы освещающей этот момент. Однако в журнальных обзорах производительности мат.плат, для UDMA33 цифра 13M/s подтверждается. Может арбитраж PCI шины "отъедает" себе кусок, может синхронизация памяти PC100 и некратная ей скорость PCI 33M/s. Это сейчас неважно. Чем же вообще задать эту скорость, например принудительно понизить.

Официально существует два пути.

Со стороны IDE контроллера, командой SET FEATURES. Со стороны чипсета, установкой соответствующих бит PCI IDE контроллера, но это требует описания установок чипсета. Что на это сказать - "Пробовали! Не получается!" Запрет UDMA в SETUP тоже игнорируется, правда он использует те же биты чипсета. Трансфер держится на 13, как будто других значений в природе не сущесвует. Может это связано с тем, что понижать скорость ниже UDMA33 нельзя, т.к. более медленный DMA Mode 2 с 16.6 M/s работает с другими сигналами на IDE шине (для режимов UDMA, часть управляющих сигналов в кабеле, меняет свое назначение). Может для ухода с UDMA66 на 33 и сработает? Кстати, если у вас нет UDMA, но есть PCI IDE Bus Master (инициализация это проверяет), то вы можете использовать данный драйвер, но в упомянутом DMA Mode 2.

Далее проверяется наличие дисков в системе и их емкость, точнее количество секторов. Это практически то, для чего раньше использовался CMOS. Хранимые в нем типы Hard дисков, а позднее их подробные параметры как то Цилиндры, Головки, Сектора, на размере более 8.4G потеряли смысл и ставятся на максимально рекомендованые значения (не превышать 1024 цилиндра). Единственно значащим параметром становится общее количество секторов. Все данные о диске прописаны в таблице параметров, которые можно получить по команде IDENTIFY DEVICE. Работает только в PIO режиме. В словах 60-61 (десятичное) и находится искомое количество секторов. Даже если в CMOS указать на диск NONE, то диск все равно будет корректно определятся. Ныне CMOS драйверу не указ. Windows'ы 9Х, кстати, так и поступают.

Для простоты драйвера, предполагается, что все исправно и корректно работает. Традиционные драйвера, при инициализации, не получая сигнала готовности от устройства, подают ему команду сброса и повторяют попытку. Данный драйвер, в этом случае, просто считает устройство несуществующим.

Из-за того, что стартовый адрес Dos Extender'а в памяти может менятся и определяется значением _code32a, требуется контроль за границей PRDT. В случае пересечения 64К, берется смещеное значение PRDT.

    PRDT dd 21 dup (0) ;4 PRDT + 4 Shift if cross 64K + 13 Push buff
    AddrPRDT dd ? ;LOGICAL Address PRDT
[/list]PRDT1 dd 21 dup (0) ;4 PRDT + 4 Shift if cross 64K + 13 Push buff[/list]
    AddrPRDT1 dd ? ;LOGICAL Address PRDT1

13 DWORD резервируется для "пропихивания" значений в физическую память сквозь буферы чипсета (кеш на этот момент запрешается через CR0). Возможно это излишняя перестраховка, но описания где регламентировалось бы поведение чипсета в подобных ситуациях найти не удалось.

При работе по прерываниям необходимо предусматривать случай когда по каким-то причинам прерывание не происходит (например в программе употребилась команда CLI, а STI забыли). Необходимо во избежание зависания, как-то контролировать подобную ситуацию. Обычно для этого используется системный таймер, но перехватывать еще одно прерывание автору было лень, да и сказалась привычка запрещать таймеры для счетных задач, чтоб ресурсы дуром не отъедали (для этого служит вызов подпрограммы _setmask8259, у которой 1 в бите AX запрещает соответствующее прерывание). Для этой цели был выбран несколько экзотичный для прикладного программирования Time Stamp Counter. Это 64-битный регистр считающий такты процессора, и используемый обычно для оценки эффективности фрагментов программы. Это создает зависимость таймаута от тактовой частоты процессора, но важно наличие самого таймаута, а будет он 1 минуту или 1 секунду, уже не суть важно, ведь он отрабатывает только в нештатных ситуациях. Выбирая контрольный бит TSC можно менять таймаут под конкретный процессор. Например для вышеупомянутой машины, бит 31 TSC дает таймаут в 7 секунд. Биты старше 31 в данном варианте драйвера использовать нельзя, они попадают в регистр EDX, а контролируется только EAX. Задействовать одновременно оба контроллера под TSC невозможно, ведь TSC один. Правда перейти на системный таймер не столь уж трудно, но необходимости в этом у автора не возникало (между прочим, упомянутую выше ситуацию с CLI системный таймер отработать не в состоянии, ведь запрещаются ВСЕ прерывания, а TSC пожалуйста. Кстати, поэтому во всех многозадачных ОС, пользователю запрещена команда CLI). В общем, даже название примера драйвера так и осталось TSC.

Казалось бы, вместо таймаута достаточно зациклить опрос бита Active регистра состояния Bus Master контроллера, и нечего морочить голову, да и прерывания становятся вообще не нужны. Однако, сие не так. Постоянный опрос (Polling) порта в/в настолько загружает шину, что скорость передачи падает в 3 - 4 раза.

Ну и наконец, как делать вызов. Какие параметры передавать и что получать. Предложеный вариант похож на Int 13h, правда с существенной особенностью. Счетчик секторов может быть любого, не вылезающего за пределы диска, размера т.е. за один вызов могут идти множественные обращения. Как упоминалось, у контроллера счетчик всего лишь 8-разрядный.

ВАЖНО!!! В этой подпрограмме НЕ используется команда WBINVD очистки кеша. Она должна следовать за операцией чтения с диска и предварять операции записи. Команда эта долгая и в некоторых случаях ненужная. Например перепись файла с одного места на другое, или копирование дисков. Данные и так в физической памяти, процессор их не трогает, так зачем дуром время терять.

Code:
;------------------------------------------------------------------------------
; IDEBusMast - Physical Read and Write.
;------------------------------------------------------------------------------
;Input: LBA ONLY !!!
;EAX = Bits 31, 29 - reserved for future use, must be 0,
; Bit 28, 30 - unused, must be 0,
; Bits 27 - 0 - LBA Address,
;BH = 0 Read, BH = 2 Write, (No change! Other value damaged driver),
;BL = Drive (80h - Master 0, 81h - Slave 0, 82h - Master 1, 83h - Slave 1.),
;ECX = Sector Count, may be more than 256,
;EDI = Physical Memory Address for transfer data.
;
;Output: CF=0 Successfull, in EDI input value, other input registers cleared,
; CF=1 Error, in AL errorcode, input registers undefined.
;Software detect errors:
;AL = 1 Timeout over (No Interrupt),
;AL = 2 Invalid Drive number in BL,
;AL = 3 LBA Address + Sector Count too big for this drive,
;AL = 4 No drive,
;AL = 5 Invalid Op. code in BH.
;AL = 6 EDI Odd. (must be aligned 2)
;Hardware errors:
;AL = 10h Device not Ready,
;AL = 11h Device Busy,
;AL = 12h Not cleared DRQ (previous operate no complete),
;AL = 13h Device Fault,
;AL = 14h Abort command,
;AL = 15h Uncorrectable Read Error,
;AL = 16h UDMA CRC Error,
;AL = 17h Sector Address out of range,
;AL = 18h No Media (for removable),
;AL = 19h Media Change (for removable),
;AL = 1Ah Media Change Request (for removable),
;AL = 1Bh Write Protect (for removable),
;Bus Master errors:
;AL = 20h IDE Bus Master Active (previous Bus Master operate no complete),
;AL = 21h Error IDE Bus Master,
;
;AL = 40h Unrecognized Error.
;------------------------------------------------------------------------------

Данная подпрограмма пользуется упомянутыми выше константами, устанавливаемыми процедурой инициализации.

Однако работать прикладной программой прямо на физическом доступе к диску где есть и другая информация, опасно. Ошибка шутя угробит всю систему. Безопаснее работать в выделенном для задачи разделе. Для чужих разделов можно например назначить атрибут "только чтение", и даже ошибочная запись обойдется без последствий. Адресация в разделе относительная, с 0 в его начале. В традициях Dos раздел объявляется "Логическим диском" и ему присваивается буква. Самому создать "не Dos" раздел можно вручную DiskEditor'ом. Задав в Partition Table начальные и конечные значения Цилиндров и т.п., затем отмечаете раздел и даете команду Calculate Partition для пересчета секторов (две последние графы Partition). Вообще, рабочими для вас являются только эти две последние графы. Именно в них и сидят стартовые LBA адреса разделов (предпоследняя) и число секторов в разделе (последняя). Для себя, Partition Table можно вообще не модифицировать, все параметры раздела вручную вносятся в программе в их описатели. Пример создания описателей для четырех разделов ниже.

Code:
Partitions dd 4 ;!!! How many partitions on all drives.

;Partition descriptor for drive 'C'

PartitionLetter db 'C' ;!!! Caps only. Compared with BL in ReadWrite.
PartitionDrive db 80h ;!!! 80h-Master0, 81h-Slave0, 82h-Ma.1, 83h-Sl.1
PartitionAttrib db 02h ;!!! 0 - Read/Write, 2 - Read Only,
PartitionType db 06h ;??? Type partition in Master Boot Record (MBR)
PartitionStart dd 3Fh ;!!! Start LBA address of partition
PartitionSize dd 0FB000h ;!!!
PartitionEnd dd 0FB040h ;!!! PartitionStart + PartitionSize + 1

;Partition descriptor for drive 'D'
db 'D' ;!!! PartitionLetter
db 80h ;!!! PartitionDrive
db 02h ;!!! PartitionAttrib
db 05h ;??? PartitionType
dd 0FB040h ;!!! PartitionStart
dd 01F9F40h ;!!! PartitionSize
dd 02F4F41h ;!!! PartitionStart + PartitionSize + 1

;Partition descriptor for drive 'E'
db 'E' ;!!! PartitionLetter
db 80h ;!!! PartitionDrive
db 0 ;!!! PartitionAttrib
db 47h ;??? PartitionType (type 47h possible free)
dd 0308946h ;!!! PartitionStart
dd 07E3E42h ;!!! PartitionSize
dd 0AEC789h ;!!! PartitionStart + PartitionSize + 1

;Partition descriptor for drive 'F'
db 'F' ;!!! PartitionLetter
db 80h ;!!! PartitionDrive
db 0 ;!!! PartitionAttrib
db 47h ;??? PartitionType
dd 0AEC789h ;!!! PartitionStart
dd 08311A6h ;!!! PartitionSize
dd 0131D930h ;!!! PartitionStart + PartitionSize + 1

Здесь первые два раздела DOS, в них запись запрещена. Два последних раздела рабочие. Можно создать фрагмент програмы инициализации, которая будет сама переносить данные из Partition Table в эти описатели, но на данный момент нужды в этом не возникало. Незадействованный параметр PartitionType соответствующий индикатору файловой системы в Partition Table зарезервирован на случай продолжения развития этой программы и создания под нее собственной файловой системы (список номеров и их сооветствия типам FS прилагается к стандартам). Создаваемая в Голландии подобная простая однозадачная V2_OS остановила эти планы, хотя возможно и не окончательно. Буквы присваиваемые разделам должны идти подряд начиная с 'C' и являются фактически порядковыми номерами, что исключает произвольное назначение их, разделам (это отражено в ошибке 83h). Логический вызов таков:
Code:
;------------------------------------------------------------------------------
; ReadWrite - Logical Read and Write (in partitions).
;==============================================================================
;Input: LBA ONLY !!!
;EAX = Bits 31 - 28 - unused
; Bits 27 - 0 - Start Sector Address
; (address in EAX calculate relative selected partition
; EAX = 0 - begin of partition),
;BH = 0 Read, BH = 2 Write,
;BL = Letter of Partition ('C' - First, 'D' - Second, 'E' - Third, etc.),
;ECX = Sector Count, may be more than 256,
;EDI = Physical Memory Address for transfer data (if you like logical - change)
;
;Output: CF=0 Successfull, in EDI input value, other input registers cleared,
; CF=1 Error, in AL errorcode, input registers undefined.
;Errorcode 1 - 40h see IDEBusMast.
;ReadWrite errors:
;AL = 80h Address + Sector Count too big for this partition.
;AL = 81h Invalid Letter in BL.
;AL = 82h No Partition with this Letter.
;AL = 83h No equal letters in BL and Partition descriptor.
;AL = 84h Write to Write Protected Partition.
;------------------------------------------------------------------------------

В эту подпрограмму WBINVD включена.

Пример драйвера и вызывающей его головной программы которая заполняет всю Extended память тем, что идет с начала диска 'C' приведен в файле TSC.ASM. Dos Extender с которым она должна компоноваться START32.OBJ. Если нужны его исходники - адрес авторской странички указан в начале этого текста, там же ReadMe к Dos Extender'у и отладчику. Программа вызывает после инициализации отладчик, что позволяет пошагово проследить ее работу. Правда пошагово отслеживать собственно момент передачи данных нужно очень быстро, чтоб не вылететь по таймауту. Для отключения отладки выкиньте из ассемблерного текста INT 1. Собственно драйвер можно выделить в отдельный obj, или вообще пхнуть его в "тело" Dos Extender'а. Для компиляции и компоновки использовался TASM. К сожалению автору так и не удалось адаптировать Dos Extender к NASM, который не хочет корректно считать EXTERNAL адреса. Попытка обратиться за помощью к создателям закончилась вообще неожиданно. Автору заблокировали доступ к страничке NASM (впрочем по информации встреченой в конференциях, автор оказался не единственным, кого постигла чаша сия)

И последнее. Программа не "обкатана" на возможные ошибки и к операциям записи следует подходить с осторожностью (см. начало этого текста). Впрочем у автора все записи даже на физическом уровне пока попадали именно туда куда следует. Работа в случае когда в системе несколько Hard дисков ВООБЩЕ пока не проверялась.

Если интересуетесь файловыми системами, и вообще структурами всевозможных ОС, то рекомендую великолепный их обзор, причем начиная с доисторической эпохи в книге "Операционные Системы" Т.Б. Большакова и Д.В. Иртегова, доступной как в HTML, так и LaTex формате на станичке:
http://www.cnit.nsu.ru/~fat/osbook.html

(они даже написали статью типа "опыт автоматического конвертирования tex -> html").

Колесницкий В.М.

E-mail: kolesnitsky@caucasus.net


30 Jul 2007 11:10
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 23 posts ]  Go to page 1, 2  Next

Who is online

Users browsing this forum: No registered users and 20 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software.