Делал монитор для V86. О них, как понял, мало где написано, и пишут в основном кратко, для общего развития. Нашел несколько интересных моментов. Знаю, что есть битовая карта перенаправления прерываний, но, согласно книжкам, она появилась только на пнях. На процах постарше подобный механизм осуществлялся программно. На вектор 0Dh цеплялся монитор, который "отсеивал" нарушения защиты, передавал управление на обработчики реального режима, при этом записывая в стек V86 адрес следующей за INTом команды (если int 3 | int 4, то EIP+1, иначе EIP+2). Как я понял, в случае с виртуальным режимом получается обязательное ограничение: DPL шлюзов прерываний PM должно быть 2 или ниже, поскольку CPL V86-го устанавливается равным 3-м и это железно (не знаю, это железно или можно как то управлять и привелегиями V86). Как "отсеять" нужные эксепшены - по коду ошибки. По нижним трем битам в коде ошибки видно, что источник нарушения - селектор в IDT, нарушение произошло при программном прерывании. Остальные биты - сам селектор. Находящиеся с стеке EIP, CS корректируются адресом, читанным из таблицы прерываний реального режима. Затем - add ESP+4 и iretd. Управление попадает на обработчик прерывания реального режима и у него в стеке уже лежит нужный адрес возврата. А точнее 6 байт - IP, CS, Flags, которые туда положил монитор в обработчике #GP. Очень сильно потрепало нервы то, что при передаче управления через шлюз в стек заносятся не только EIP, CS, EFlags, но и ESP, SS, ES, DS, FS, GS. Как то упустил из вида. %)
Подтверждаю что CPL=3 в VM. Нао учесть что при любом прерывание если процессор находиться в VM. Вызывается обработчик прерывания. Так вот DS не определен. Незабываем что у нас еще есть хардварные прерывания как то таймер и клава с мышью. Если это запрещенная команда. Как то int то там будет 0. А если ошибка произошла в результате выполнения переключения задачь, вызов шлюза то будет код ошибки. Я на этом форуме уже задовал вопрос про VM. Собственно тогда сглупил, напутал с преобразованием адрессов 16битной и 32битной. Еще надо помнить что в 86 сегмент имеет границу 64КБ и нужно делать обработку. Катоты не скозал что для отлова прерываний надо устанавит IOPL в 0. Еще я с NT флагом не очень разобрался.
Неверно. 1. Если IOPL < 3, то DPL шлюза вообще никакого значения не играет, а процессор просто делает #GP(0) независимо ни от чего. 2. Если IOPL = 3 и DPL шлюза меньше 3, это #GP(selector). 3. Если IOPL = 3 и DPL шлюза равен 3, то вызывается обычный PM обработчик. Обработчику может быть даже неважно, откуда именно он вызван: из V86 или из PM. Команда iret сама определит, куда нужно вернуться. Но обработчик может легко определить, что он вызван из V86: в этом случае в образе EFLAGS на стеке [esp+12] установлен бит VM (20000h).
diamond причем здесь IOPL? DPL шлюза не влияет на вызов обработчика исключения или аппаратного прерывания
rei3er IOPL здесь при том, что речь идёт о V86, а в этом случае это важно. Безусловно. Но мне показалось, что речь идёт как раз-таки о программных прерываниях и об их обработке в V86.
влияет на алгоритм работы команды IRET. Если он установлен, то задача была запущенна другой задачей, IRET - выполнит обратное переключение, т.е. на задачу, селектор TSS которой указан в первом поле TSS текущей задачи. Иначе, IRET выполнит обычный возврат из обработчика прерывания.
По поводу IOPL: Насколько я понимаю, уровень привелегий ввода-вывода касается не только V86, но и обычных задач. Когда значение IOPL меньше CPL, привелегированные команды типа In/Out, pushf/popf будут вызывать #GP(0). И это независимо от флага VM. Я правильно рассуждаю? Команда int будет вызывать исключение #GP(selector) каждый раз, когда значение DPL шлюза меньше значения CPL задачи, натворившей int. Причем независимо, является ли задача V86 или нет. так? И остается еще один размытый момент - что вытворяет проц со стеком при передаче управления на обработчик прерывания? Вот что сложилось в голове после нескольких экспериментов: Если это V86, DPL шлюза прерывания <3 - происходит #GP(селектор) и происходит повышение привелегий, т.е. переключение на более привелегированный стек. В стек кладутся GS, FS, DS, ES, |сюда, по идее, могли бы копироваться параметры, если бы были указаны в шлюзе|, SS, ESP, eflags, CS, EIP, err_code. Если DPL шлюза =3, вызывается соотвествующий обработчик из IDT, потому как нарушения привелегий нету. вызов из V86 можно определить по флагу VM. Если это не V86, а простая задача, выполняемая в 3-м кольце. Не зависимо от того, было ли нарушение командой int или нет, факт тот, что есть повышение привелегий. В стек будут занесены SS, ESP, eflags, CS, EIP, (err_code, если надо). Такая ситуация определяется по: RPL селектора CS, который в стеке, ниже CPL внутри обработчика. Если же при выполнении int не было повышения привелегий, то в стек будут занесены только eflags, CS, EIP, (err_code, если надо). При этом RPL селектора CS, который в стеке, равно CPL внутри обработчика. Кто что думает?
Barbos Есть привелегерованные инструкции который вызывают исключение при CPL <>0. в VM CPL=3 всегда. Есть чувствительные к IOPL инструкции к дополнению имеющимся привелегированные инструкции. CLI, STI, PUSHF, POPF, INT n, and IRET. GP(0) если IOPL<CPL Что касается In/Out то они чувствительны в защищенном режиме, но не чувствительны в VM. Зато их можно ловит по битовой карте. Два способа выставлин бит в 0. Или лимит задачи сделать корочи так чтобы битовая карта в него не поподала. А дальше вроде правельно. Вот только нужно еще разлечить вызов ошибки с err_code, от вызова прерывания в VM режиме по int.
Во-первых, очень хочется заметить, что слово "привилегий" пишется через 'и'. 1. cli и sti вызывают #GP(0) при IOPL < CPL (в V86, как уже было сказано, всегда CPL=3) и нормально выполняются при IOPL >= CPL. Это относится как к V86, так и к PM. 2. pushf и popf в PM не вызывают исключения (клинические случаи типа нехватки стека не рассматриваются), но popf модифицирует не все биты eflags. pushf и popf в V86 при IOPL=3 не вызывают исключения, но опять же модифицируются не все биты (конкретнее, из младшего слова не меняется IOPL; более полный список - см., например, второй том мануалов Интела). pushf и popf в V86 при IOPL<3 вызывают #GP(0). 3. int в V86 при IOPL<3 всегда вызывает #GP(0). Во всех остальных ситуациях - да, идёт проверка уровня привилегий, и если его недостаточно, то #GP(selector). Кстати, при вызове прерывания из V86 DPL шлюза должен быть нулём, иначе произойдёт #GP(new code selector). Всё верно. При выходе из V86-режима в защищённый всегда происходит переключение стека, и на новый стек кладутся V86-значения сегментных регистров ds,es,fs,gs, а сами эти регистры обнуляются (поскольку их V86-значения некорректны в PM). А дальше механизм один и тот же для V86 и PM: если есть повышение привилегий (а для V86 оно всегда есть), то старые значения ss:esp кладутся на стек, а новые берутся из TSS; далее eflags и cs:eip, и далее, возможно, код ошибки.