Все несколько сложнее, но уже работает24.06.04 13:17 Число просмотров: 1863 Автор: leo <Леонид Юрьев> Статус: Elderman Отредактировано 24.06.04 17:24 Количество правок: 2
Все несколько сложнее. KeStallExecutionProcessor() просто старается приостановить текущий CPU на заданное количество микросекунд. А мне нужна пауза при запрещенных прерываниях, поэтому проше просто запретить прерывания и зациклить "не нужные" процессоры while(flag != done){DoCpuPause();}. Реализация самой паузы тривиальна, самое главное войти в режим паузы, тут и начинаются хитрости.
Сложность в том, что прерывания нужно запрещать синхронно и одновременно на всех процессорах, либо использовать IPI для взаимодействия между CPU. Само ядро конечно использует второй вариант, но мне IPI не доступен.
Одновременно запрещать прерывания (cli) нужно потому, что обработка прерывания на одном процессоре может потребовать IPI-обращения к другому. Например для постановки DPC в очередь или для вызова обработчита прерывания драйвера устройства. Кроме того, постановка моих "пусковых" DPC в очередь также требует IPI. Если при этом на "другом" процессоре прерывания уже запрещены, то IPI-запрос не будет обслуживаться, а первый процессор будет ждать сего факта (причем в это время на нём самом прерывания уже будут запрещены). В итоге cli на одном процессоре может легко остановить всё остальное.
Запретить прерывания на всех CPU одновременно конечно невозможно, но можно организовать кратковременное ожидание факта выполения всеми CPU нужного кода при cli. И соответственно повтор неудачных попыток. Вот так сейчас и работает, см. картинку.
Еще одна хитрость в том, что пользоваться штатным отладчиком нельзя. Даже просто вызов DbgPrint() может намертво завесить систему. Работать может только а-ля softice с аппаратным прицепом.
--- Прошу прощенья за кросс-постинг, но в [hacking] многие не заглядывают.
Нужно пройтись по регистрам чипсета, поэтому необходимо заблокировать прерывания на всех процессорах. На SMP-системах это не совсем просто...
Я пока сделал через interlocked-зацикливание в DPC, на "идеальном" SMP это всегда работаеет. Но на многих SMP-системах не каждый процессор может непосредственно послать IPI (поставить DPC в очередь) к любому другому, и в результате система может зациклиться.
> --- Прошу прощенья за кросс-постинг, но в [hacking] многие > не заглядывают. > > Нужно пройтись по регистрам чипсета, поэтому необходимо > заблокировать прерывания на всех процессорах. На > SMP-системах это не совсем просто... > > Я пока сделал через interlocked-зацикливание в DPC, на > "идеальном" SMP это всегда работаеет. Но на многих > SMP-системах не каждый процессор может непосредственно > послать IPI (поставить DPC в очередь) к любому другому, и в > результате система может зациклиться. > > Кто-нибудь знает про готовые решения? Я могу ошибаться, но если я правильно понял, то достаточно поднять IRQL(Level) до необходимого тебе уровня тогда все прерывания приоритетом ниже буду заблокированны.
Если поднять irql до high_level на всех процессорах - то...09.07.04 14:58 Автор: leo <Леонид Юрьев> Статус: Elderman
> Я могу ошибаться, но если я правильно понял, то достаточно > поднять IRQL(Level) до необходимого тебе уровня тогда все > прерывания приоритетом ниже буду заблокированны.
Если поднять IRQL до HIGH_LEVEL на всех процессорах - то конечно да. Но KeRaiseIrql() делает это только для текущего процессора. Поэтому для UP проблем нет никаких, а на MP совсем не просто.
Блокировка прерываний броликует и IPI (Inter-Processor Interrupt), поэтому "общение" между процессорами тоже блокируется. Заблокировать прерывания одновременно на всех CPU не возможно в принципе, а обработка прерывания на одном процессоре может потребовать IPI к другому. Об этом я уже писал в других постах.
надо создать нужное число потоков (по количеству...10.07.04 19:57 Автор: cb <cb> Статус: Member Отредактировано 10.07.04 19:59 Количество правок: 1
> Если поднять IRQL до HIGH_LEVEL на всех процессорах - то > конечно да. Но KeRaiseIrql() делает это только для текущего > процессора. Поэтому для UP проблем нет никаких, а на MP > совсем не просто.
надо создать нужное число потоков (по количеству процессоров) с такими affinity mask чтобы каждый из них выполнялся на своем процессоре после чего синхронно поднять на них irql до нужного уровня. один из потоков нагрузить еще и бизнес логикой - после поднятия irql выполнить то что тебе надо... мне попадалась когда-то реализация этой идеи...
cb.
имхо на threads хуже чем на dpc10.07.04 20:17 Автор: leo <Леонид Юрьев> Статус: Elderman Отредактировано 10.07.04 20:20 Количество правок: 1
> надо создать нужное число потоков (по количеству > процессоров) с такими affinity mask чтобы каждый из них > выполнялся на своем процессоре после чего синхронно поднять > на них irql до нужного уровня. один из потоков нагрузить > еще и бизнес логикой - после поднятия irql выполнить то что > тебе надо... мне попадалась когда-то реализация этой > идеи...
Во-первых создавать несколько threads - довольно ресурсоёмкая задача. Во-вторых, affinity в user-mode не совсем тоже самое что в kernel-mode. Через документированные функции affininy для kernel-thread не поставить... На ядре с realtime можно нарваться на bugcheck. А самое главное - это никак не решает проблему с необходимой синхронностью блокировки прерываний.
Поэтому я остановился на DPC. Пока работает без проблем, недостаток только один - немаленькая (100-1000 loops) interlocked-вертушка при блокировки прерываний. Но имхо по-другому без доступа к IPI никак.
да.10.07.04 21:45 Автор: cb <cb> Статус: Member Отредактировано 10.07.04 22:01 Количество правок: 1
Существует два поля affinity, одно um другое km. Насколько я понял (но не проверял) um affinity не учитывается при переключении контекстов в km, если не задано km-affinity.
ZwSetInformationThread() и KeSetAffinityThread() ставят um-affinity учитывая process-affinity для процесса данного thread. Именно KeSetAffinityThread() вызывает KeBugCheck(INVALID_AFFINITY_SET).
Еще есть KeSetSystemAffinityThread() и KeRevertToUserAffinityThread().
А если остановить «ненужные» процессоры через HAL.KeStallExecutionProcessor(), а дальше делать, как обычно?23.06.04 16:06 Автор: HandleX <Александр М.> Статус: The Elderman Отредактировано 23.06.04 16:10 Количество правок: 1
Все несколько сложнее. KeStallExecutionProcessor() просто старается приостановить текущий CPU на заданное количество микросекунд. А мне нужна пауза при запрещенных прерываниях, поэтому проше просто запретить прерывания и зациклить "не нужные" процессоры while(flag != done){DoCpuPause();}. Реализация самой паузы тривиальна, самое главное войти в режим паузы, тут и начинаются хитрости.
Сложность в том, что прерывания нужно запрещать синхронно и одновременно на всех процессорах, либо использовать IPI для взаимодействия между CPU. Само ядро конечно использует второй вариант, но мне IPI не доступен.
Одновременно запрещать прерывания (cli) нужно потому, что обработка прерывания на одном процессоре может потребовать IPI-обращения к другому. Например для постановки DPC в очередь или для вызова обработчита прерывания драйвера устройства. Кроме того, постановка моих "пусковых" DPC в очередь также требует IPI. Если при этом на "другом" процессоре прерывания уже запрещены, то IPI-запрос не будет обслуживаться, а первый процессор будет ждать сего факта (причем в это время на нём самом прерывания уже будут запрещены). В итоге cli на одном процессоре может легко остановить всё остальное.
Запретить прерывания на всех CPU одновременно конечно невозможно, но можно организовать кратковременное ожидание факта выполения всеми CPU нужного кода при cli. И соответственно повтор неудачных попыток. Вот так сейчас и работает, см. картинку.
Еще одна хитрость в том, что пользоваться штатным отладчиком нельзя. Даже просто вызов DbgPrint() может намертво завесить систему. Работать может только а-ля softice с аппаратным прицепом.