Доброго времени суток! 1. Перехватывается обработчик прерывания IRQ8 в WindowsXP. Каким образом корректно подменить регистры, сохраненные в стеке, чтобы после возврата из обработчика начал выполняться мой user-mode код? И ещё 2. Как выйти из моего обработчика корректно, не передавая управления оригинальному обработчику тем самым не запуская процесс переключения контекстов в Винде (вроде как iretd но почему-то не работает).
Расплывчатый вопрос. 1. Какой твой юзермодный код ?? DPL(CS) не известно заранее. Прерывание в контексте любого процесса произойти может.. 2. Восстановить всё, что было изменено(например сегментные регистры, стек). Обычно планировщик запускается по выходу из прерывания в HalEndSystemInterrupt().
Пытаюсь сделать вот что. В обработчике определяю, какой код выполнял процессор в момент наступления прерывания r0 или r3 (при помощи анализа сохраненных в стеке cs и flags. Если r0 - то ничего не делаю и передаю управление оригинальному обработчику. Если r3 - то по fs:[0x20] (TEB) определяю ID процесса и если это мой процесс то заменяю значение eip в стеке на адрес процедуры в контексте главного потока моего процесса. Процедура-то вызывается, но: хотелось бы, во-первых, передавать управление моей процедуре таким образом из любого контекста, в котором сработало прерывание и, во-вторых, не дать Windows переключить задачу на время выполнения (1-2 тика таймера) user-mode процедуры. Есть у кого мнение на этот счет? Прошу прощения за сумбур
Во первых процесс нужно определять через ядерные структуры, виртуальная память выгружаемая, дабы избежать голубого огонька следует вызвать PsGetCurrentProcessId(), либо из ETHREAD.Cid считать вручную. Значит тебе нужно переключить адресное пространство, тоесть аттачиться к необходимому процессу. Планировщик вызывается не только по таймеру. Все их запрети(cli) и планирование выполняться не будет. Только в этом случае не будет вызван менеджер памяти при возникновении исключения(для подкачки), также нельзя будет обращаться к системе, вызывая сервисы, даже стек наверно расширен не будет при срабатывании сторожевой страницы.. Вобжем так не делается, нельзя выполнять юзермодный код с запрещёнными прерываниями.
Верно, в Винде нет никакой возможности позволить юзермодному thread-у гарантировано не быть вытесненым втечение какого-то промежутка времени.
Zufyxe Ошибаешся, блокировать планирование не проблема, другое когда код с DPL=3 вызывается на высоких IRQL.
Поделись, пожалуиста, как сделать, чтобы мой "хелловорлд" гарантировано отработал одну секунду и не был ничем вытеснен. Варианты на тему "пропатчить ядро" и "есть такое недокументированное поле" не предлагать.
Zufyxe Знаешь ли, ядро не расчитано чтоб юзать "вторичный" код прямо из аппаратных ISR. И документированной функции KiDisableSwapContext ты не найдёшь Пошли DPC и уже из него когда IRQL будет понижен бокси мессагу, например через ядерный калбэк, или в классическом варианте APC поставь в очередь.
SashaTalakin, Мы не рассматриваем код, который периодически чего-то там ждет (если ты об этом). Скажем, есть некая "математика" в юзермоде, есть драйвер. Я лично, утверждаю в 5-м посте, что в ОС Виндовз нету легитимной возможности гарантировать, что наша "математика" будет считаться на процессоре какое-то разумное время N, и за этот период не будет вытеснена. Нету таких средств. Конечно, можно похучить несколько функций диспатчера и запретить вытеснять определенный thread. Но это будет сложное, и сильно зависимое от версии и архитектуры системы, решение. Вполне возможно, что я не прав, и что-то упустил: именно это и хотелось бы услышать. Clerk, я не особо много понял из твоего поста. В особенно непонятно про "Пошли DPC и уже из него когда IRQL будет понижен...". Когда это при обработке DPC понижается IRQL? Полностью согласен с тобой на счет того, что вызывать узермодный код на высоком IQRL, - полный ахтунг
Zufyxe DPC доставляется когда происходит понижение IRQL до DISPATCH_LEVEL. А в аппаратных прерываниях IRQL слишком высокий, на котором высокоуровневый функционал ядра не доступен. Повторяю, напрямую вызвать юзермодный код ты можешь, например закрепив страницу в памяти и передать через Iret на неё управление, но максимум что ты можешь сделать там - это выполнить код не выходящий за пределы этой страницы и не вызывая сервисы(не обращаясь к ядру), например просто увеличить значение какихто счётчиков и вернуться.
Всем большое спасибо! Действительно, так просто передать управление на юзер-моду не получится в Windows Спасибо Clerk направил на путь истинный. Зреет вопрос: как из-под юзверя залочить память чтобы не свопилась? и чтобы её драйвер "видел"? Но это уже совсем другая история ...
Код (Text): NTSTATUS NtLockVirtualMemory( __in HANDLE ProcessHandle, __inout PVOID *BaseAddress, __inout PSIZE_T RegionSize, __in ULONG MapType ) /*++ Routine Description: This function locks a region of pages within the working set list of a subject process. The caller of this function must have PROCESS_VM_OPERATION access to the target process. The caller must also have SeLockMemoryPrivilege. Arguments: ProcessHandle - Supplies an open handle to a process object. BaseAddress - The base address of the region of pages to be locked. This value is rounded down to the next host page address boundary. RegionSize - A pointer to a variable that will receive the actual size in bytes of the locked region of pages. The initial value of this argument is rounded up to the next host page size boundary. MapType - A set of flags that describe the type of locking to perform. One of MAP_PROCESS or MAP_SYSTEM. Return Value: NTSTATUS. STATUS_PRIVILEGE_NOT_HELD - The caller did not have sufficient privilege to perform the requested operation.