Приветствую! Моя задача следующая - выяснить, с некоторыми подробностями, в какой среде запустили exe-шник со встроенным DOS32A, т.е. это программа защищенного режима для DOS с DOS-extender-ом. Пока суть такова - при запуске выясняем, в Windows мы или в DOS. Затем, если в Windows, то пытаемся узнать, в какой версии, по крайней мере, имеется в виду линейка NT. Все это можно выяснить при помощи серии фиктивных вызовов Native API. Однако, как было где-то здесь на форуме экспериментальным путем выяснено и подтверждено, int 2Eh под NTVDM не работает так, как ожидается, т.е. вызов Native API не производится, хотя первый этап (DOS или Windows) таким образом пройти все равно можно. Другой способ - SYSENTER - работает в NTVDM, определение версии Windows проходит на ура, однако после первого же выполнения SYSENTER (и возврата из ядра) среда перестает быть такой, какой была ДО выполнения SYSENTER. Пока я выяснил, что: 1) отваливается DPMI API - тот самый, который предоставляется прослойкой DOS32A; любой вызов int 31h приводит к ошибке NTVDM; 2) DOS API, по крайней мере функции вывода на экран, продолжают работать, как ни в чем не бывало, даже при перенаправлении вывода в файл; 3) отваливаются порты ввода-вывода, по крайней мере команды типа out вызывают ту же реакцию системы, как и в п.1. 4) команды SIDT/SGDT/SLDT/STR показывают одни и те же значения - что до SYSENTER, что после; сегментные регистры я сохраняю и затем восстанавливаю; само собой и ESP на месте. Вопрос - а что собственно происходит? Что еще можно проверить на предмет изменений? И еще - можно ли все вернуть взад (т.е. порты, DPMI и т.д.), и если да, то как?
Я конечно неособо грамотный для тебя вариант предложить хочу ибо не профи в етом и все дела, нощас у сех стоит либо виста либо семерка хпшек осталось ой как немного, если тебя интересует чистый дос то он не поддерживает 32битные регисторы, во время ошибку можешь смело прыгнуть на секцию кода для виндовс NT ибо 98 врятли ты щас где найдешь , помойму вариантов тут много и ты все просто усложняешь и совсем понятно с какой целью. Можно было бы еще включить в прогрмму проверку на Wine, WMware...
А разве код, выполняющийся с EFLAGS.VM вообще может исполнять инструкции защищенного режима? Насколько я помню, регистры и инструкции защищенного режима вообще не доступны в V86.
А флаг VM и должен быть сброшен, я не зря написал про DPMI - перед запуском непосредственно "пользовательского" кода DOS32A подготавливает для него среду защищенного режима с плоской моделью памяти, в том числе и с обработчиками программных прерываний для перенаправления некоторых из них в V86 (тот же int 21h или int 10h). Т.е. SYSENTER я выполняю уже из 32-битного защищенного режима, но в окружении DOS-экстендера. А после выполнения SYSENTER int 31h (DPMI API) уже не работает (выдает ошибку NTVDM), также не работает ввод-вывод в порты. В итоге 2 вопроса - какого фига? и как исправить?
Clerk Ykidia Я не об этом, меня удивляет, как будет работать экстендер в v86. Если я правильно помню, то он просто не сможет переключить процессор в защищенный режим: инструкция 'mov cr0, eax' должна сгенерировать #UD.
Ykidia Это V8086 режим, тоесть аппаратный эмулятор. Для доступа к портам нужно чтоб IOPL = 3, ну или IOPM настроена(уже не помню как там с вдм).
Mika0x65 Под NTVDM экстендер всего лишь перенаправляет запросы в DPMI, предоставляемый NTVDM, так что конфликта нет; если же экстендер запускается в среде, где нет DPMI, то он предоставляет его самостоятельно. Я говорю про этот Clerk Нет, это НЕ V86. V86 - это только при запуске NTVDM. Но затем, при помощи DPMI, который имеется в NTVDM (или через экстендер), я могу перейти в защищенный режим с вожделенным IOPL=3 (кстати для безоговорочного доступа к портам нужен IOPL=0, а при IOPL=3 уже нужна битовая маска портов, разрешающая доступ к конкретным портам). Экстендер делает работу по переходу за меня, в итоге при запуске своего exe-шника я уже нахожусь в PM с IOPL=3; также он делает за меня работу по переназначению привычных int XX из защищенного режима в V86. При старте своей проги под NTVDM с экстендером, кроме PM с IOPL=3 я имею: 1) более или менее свободный доступ у портам (NTVDM либо эмулирует, либо "пропускает", как минимум это порты PS/2, VGA и SB); 2) эмуляцию привычного окружения вызовов DOS: экстендер перенаправляет большинство вызовов int 10h/21h/33h в DOS, который, в свою очередь, эмулируется NTVDM. При таком перенаправлении учитывается трансляция адресов из формата PM в формат RM и обратно (по документации); 3) DPMI API, позволяющий мне делать то, что нельзя или затруднительно с помощью пп.1-2. После выполнения команды SYSENTER я имею другую картину: 1) доступ к портам запрещен; 2) эмуляция привычного окружения вызовов DOS вроде остается - как минимум вывод на экран работает; 3) DPMI API отсутствует. Я думал, может кто знает и/или сталкивался - в чем причина и как вернуть пп.1 и 3 на место.
Ykidia Не понятно ничего. Во первых что за переключения между режимами, Win95 ? Во вторых IOPL - он должен быть выше чем CPL, тогда всё пространство I/O доступно, иначе начинает работать маска в IOPM.
Clerk А, да, забыл подробности. Вот вроде нашел: Выполнение команд ввода/вывода разрешено, если CPL <= IOPL. При CPL > IOPL производится проверка содержимого битовой таблицы разрешения ввода/вывода. Ну мне пофиг - работает же все до выполнения долбаного SYSENTER. Т.е. есть подозрения, что после - IOPL стал меньше 3? Надо будет проверить, бляймух... А что тогда происходит с DPMI API (int 31h), он-то куда девается? Это не зависит от версии Windows, важно, что его окно DOS поддерживает DPMI, почти полностью (в т.ч. и переход в защищенный режим и обратно). В моем случае это делается автоматитьки экстендером, так что я могу не страдать болезнью "делать все вручную", как это было когда-то.
Ykidia Вы обращаетесь к ядру через Sysenter. Прежде VM = 1. Иначе никакие сервисы DPMI и остальная дос-надстройка не доступна. Далее вызов Int 0x32 должен сгенерировать #GP.
Перед выполнением SYSENTER по расписанным мной выше причинам VM=0. Я может чего-то и подзабыл, но не выжил еще из ума, иначе почему я тогда работаю с селекторами (смещениями в LDT), а не параграфами, и размер всех сегментов = 4G (кроме PSP, селектор которого при запуске загружен в ES, и его размер ограничен вроде 256 байтами)? И программные прерывания в защищенном режиме никто не отменял, они хоть и работают по-другому, но экстендер транслирует в привычные вызовы. Но после SYSENTER int 21h продолжает работать, а int 31h уже нет... P.S. а вот если меняется IOPL, тогда уже никак не исправить :mad:
Ykidia Програмный эмулятор, который отвечает за трап-процессинг в NT выполняет эмуляцию только если VM = 1 и VdmObject установлен у процесса. Что вы там наделали не знаю.) Вот например начало #GP: Код (Text): public _KiTrap0D _KiTrap0D proc ; ; Did the trap occur in a VDM in V86 mode? Trap0d is not critical from ; performance point of view to native NT, but it's super critical to ; VDMs. So here we are doing every thing to make v86 mode most ; efficient. .errnz (EFLAGS_V86_MASK AND 0FF00FFFFh) test byte ptr [esp]+0ch+2,EFLAGS_V86_MASK/010000h jz Ktdi KtdV86Slow: ENTER_TRAPV86 kitd_a, kitd_v KtdV86Slow2: mov ecx,PCR[PcPrcbData+PbCurrentThread] mov ecx,[ecx]+ThApcState+AsProcess cmp dword ptr [ecx]+PrVdmObjects,0 ; is this a vdm process? jnz short @f ; if nz, yes sti ; else, enable ints jmp Kt0d105 ; and dispatch exception @@: ; Raise Irql to APC level, before enabling interrupts RaiseIrql APC_LEVEL push eax ; Save OldIrql sti stdCall _VdmDispatchOpcodeV86_try,<ebp> KtdV86Exit:
Clerk Так ведь в моем случае эмуляция производится через DPMI, т.е. int 21h, к примеру, вызывает обработчик соответствующего прерывания защищенного режима, а тот уже проверяет, какой вызов, при необходимости подготавливает сегментные регистры и смещения и передает вызов в V86 посредством функции 0300h "вышестоящего" DPMI (который предоставляется NTVDM-ом). В случае с NTVDM-ом дальнейшего переключения в V86 нет, вместо этого делаются соответствующие вызовы сервисов ОС. А если бы я не пользовал DPMI/экстендеров, то конечно же торчал бы в V86, и все происходило бы именно так, как Вы говорите. И любой int вызывал бы в первую очередь #GP, как у Вы и пишете. Когда-то мне приходилось эмулировать DOS в V86 - такой геморрой! Еще и этот himem.sys, для работы кода которого мне приходилось временно отключать защиту или что-то такое делать. И все конечно это хорошо, да только нафиг не нужно, ибо уже сделано - DPMI в таких случаях рулит.
Ykidia Вот именно, V86 это рудимент и всё что с этим связано, который введён для совместимости и сейча наверно только в стенах учебных заведений юзается. Ядро вызывается через шлюзы, когда окружение нормальное, либо V86. Вызовы из всяких промежуточных режимов, не допустимы, это битая среда. Например вы не можите вызывать сервисы не из контекста или с не запущенным ядром.
Проверил - как до, так и после выполнения SYSENTER значение поля IOPL=0. Значит, доступ к портам в V86 полностью контролируется (что логично), но не с тотальным запретом, а с эмуляцией. Какие-то порты эмулируются простой передачей из/в физические порты (как минимум это порты VGA и, скорее всего, PS/2), что не совсем безопасно, ибо, скажем, некоторые "безобидные" на первый взгляд манипуляции с портом PS/2 могут заморозить мышь в Windows до перезагрузки. Итак, VM всегда 0 (имеется в виду после переключения в PM при помощи DPMI), IOPL всегда 0, другие параметры тоже на месте - сегментные регистры и регистры IDTR/GDTR/LDTR/TR. Вроде как обработчик 21h остается тот же, даже некоторые специфические вызовы DOS32A работают, но в общем и целом большинство привычных вызовов, работающих до SYSENTER, после - уже не работают, а вываливают DOS-сессию в ошибку. Соответственно, есть подозрения, что и другие обработчики должны быть на месте (тот же 31h), просто они аналогично обламываются с ошибкой. Что еще можно посмотреть на предмет изменений?
Оказалось, что SYSENTER и дальнейшие манипуляции в ядре некорректно восстанавливают CS (и вроде как SS). Восстановил (CS с помощью IRETD, а SS просто со стека), и все вернулось на свои места. Уф...
Ykidia Разумеется что диспетчер восстанавливает сегментные регистры. При смене кпл формируется нормальный трап-фрейм в случае быстрых вызовов. Предполагалось что сегменты у вас нормальные. Кстате вы можите использовать 0x2A прерывание для создания дескрипторов в LDT, если у вас Cs отличен от дефолтного.
Тут я ничего менял, что мне DPMI выдал, тем и пользуюсь. Идиотский вопрос - а в WinNT и Win2k SYSENTER как себя проявляет? Насколько я знаю, там-то нужные MSR не проинициализированы?