2) Тогда всё ещё впереди. Отрицательных результатов не гарантирую (хотя и такое бывает), но нулевые будут точно. Что-то меня на цитаты тянет... О, сколько нам открытий чудных Готовят просвещенья дух, И опыт, сын ошибок трудных... 5) Если так определять абсолютные плюс и минус, то не в нашей власти выбирать, к какому из них двигаться - локальные изменения либо приведут к глобальным качественным, либо не приведут. Я склонен считать, что в данном конкретном случае - нет. 10) *включает лекторский тон и готовится к очередной простыне текста* Значит, так. Давным-давно был процессор 8086, был реальный режим и в этом режиме исполнялся различный код. Иногда этот код запрещал прерывания, иногда их разрешал. Прерывания запрещались по двум возможным причинам: во-первых, коду могло понадобиться, чтобы у него совершенно точно не отобрали управление на каком-то промежутке (например, опрашивает какое-то устройство, которое должно вот-вот ответить), а во-вторых, код мог просто не хотеть конкуренции с другим кодом (например, он переключает стек или выполняет нереентерабельную процедуру). Прошло некоторое время. Появился 80386. В нём уже был защищённый режим (на самом деле этот режим появился в 80286, но v86 там не было) и встал вопрос о совместимости со старым кодом, для решения которого был придуман специальный режим V86. Основная фича V86 заключается в том, что это подрежим защищённого, в котором адреса из сегментных в линейные преобразуются как в реальном режиме. Защищённый режим на то и защищённый, что в нём абы кто не имеет права обращаться напрямую к оборудованию, а доступ контролируется полем IOPL: если код не менее привилегирован, чем IOPL (численно это неравенство CPL<=IOPL), то ему разрешаются инструкции cli/sti/hlt, которые запрещают/разрешают прерывания, в противном случае эти инструкции генерируют #GP. Но cli/sti всего лишь очищают/устанавливают 9-й бит в регистре flags, а на этот регистр воздействуют ещё и команды pushf, popf, int и iret. Для нового кода просто постулируется, что при cpl>iopl popf и iret игнорируют соответствующие биты, и новый код должен быть к этому готов. Но что делать со старым кодом? Сделали так: при cpl<=iopl (что для V86-кода эквивалентно IOPL=3) cli/sti/hlt/pushf/popf/int/iret делают то, что они и раньше делали, а при cpl>iopl все эти инструкции вызывают #GP, и V86-менеджер (обработчик #GP из V86-машин) уже может сам решать, сделано ли это для того, чтобы прерывания от других устройств не мешали (и тогда глобально выключать/включать прерывания) или чтобы другой код не мешал (и тогда вне этой машины вполне себе могут выполняться прочие действия). Всё это разработчики стали обкатывать, и в конечном счёте выяснилось, что основной сценарий использования - использование этого режима для запуска старых программ в осях защищённого режима, которые с железом работают самостоятельно и программы к нему напрямую не допускают. Соответственно на практике всегда IOPL=0, нужен только второй вариант использования запрещения прерываний, для каждой V86-машины внутри системы есть флаг занятости, показывающий, что ничего другого внутри этой машины в данный момент выполнять нельзя (но можно переключаться на другие задачи). V86-менеджер при этом занят вполне фиксированными делами: распознаёт, какая инструкция вызвала исключение, эмулирует её, при cli/sti/popf/iret анализирует предлагаемое значение для IF и в соответствии с ним устанавливает/сбрасывает флаг занятости, при pushf и int подсовывает вместо "настоящего" флага IF его эмулируемое значение. Кроме того, полезно, скажем, при прерывании от таймера уведомлять об этом V86-машины, чтобы выполняющиеся там программы могли отсчитывать время, так что появляется необходимость в менеджере при разрешении прерываний доставлять какие-нибудь события внутрь V86. Наконец, довольно удобной оказалась возможность программные прерывания int N эмулировать прямо из менеджера. В результате всё это работает, но, во-первых, нужно писать некоторый обвязочный код, а во-вторых, при каждом чихе вызывать исключение - не самое быстрое решение. Опять прошло некоторое время. Инженеры из Intel на всё это посмотрели, подумали, и появился процессор Pentium, в котором в числе прочего есть расширения V86. Фактически они сводятся к тому, что то, что раньше делал менеджер V86, теперь делает сам процессор - при iopl=3 ничего не изменилось, а при iopl<3, если включена поддержка расширений, то вместо флага внутри системы появляется флаг VIF внутри регистра eflags, и cli/sti/popf/iret вместо того, чтобы вызывать #GP, обработчик которого сведётся к изменению флага занятости, сразу меняют флаг VIF. На реальный флаг IF они в полном соответствии с тем, что код непривилегированный, не влияют. Соответственно pushf на место IF подставляет VIF. С int ситуация несколько интересней, поскольку можно обеспечить и возможность вызова обработчиков [псевдо]реального режима, не выходя из V86, так и возможность перехватчиков защищённого режима, но это выходит за рамки настоящего разговора, а мануалы таки никто не отменял. Кроме того, для того, чтобы можно было доставлять уведомления о прерываниях типа таймера, sti/popf/iret, устанавливающие IF, проверяют ещё один флаг внутри регистра eflags под названием VIP, и если он установлен, то считают, что система хочет доставить прерывание, и генерируют #GP в качестве уведомления, что зажёгся зелёный свет; когда система хочет доставить прерывание, если флаг VIF в задаче сброшен, то, вообще говоря, сразу этого делать нельзя, но можно установить VIP, и процессор сам сообщит, когда появится возможность. Думаю, после всей этой лекции должно быть понятно, что к ситуации в Колибри, где V86 используется исключительно для работы с железом, VIF и VIP не имеют никакого отношения. Собственно, включать их обработку просто нельзя из-за того, что BIOSовские cli/sti должны быть реальными cli/sti. Ну а насчёт перехвата iret - при iopl<3 это происходит автоматически, ибо генерируется #GP, а в общем случае можно вспомнить, что доставкой прерывания в V86 занимается не процессор, а система, и записывать в V86-стек не настоящие cs:ip, а подложные, ведущие куда-нибудь на инструкцию, заведомо вызывающую исключение (это может быть специальный int или просто invalid opcode, главное, чтобы система помнила адрес) - тогда iret вернётся, куда ей скажут.
_________________ Ушёл к умным, знающим и культурным людям.
|