Сейчас на форуме: tyns777 (+4 невидимых) |
eXeL@B —› Программирование —› Работа ядра на 2-х и более ядрах |
Посл.ответ | Сообщение |
|
Создано: 15 июля 2010 14:45 · Поправил: DenCoder · Личное сообщение · #1 Недавно, при исследовании креш-дампа, случайно обнаружил, что на разных ядрах регистры gdtr и idtr разные. Это привлекло мое внимание и быстро обнаружилась одна проблема - gdi-функции работают только на одном ядре??? По порядку. Для начала введем в WinDbg команды, чтобы узнать на момент краша содержимое регистров на всех cpu. Для cpu0 Code:
для cpu1 Code:
Посмотрим таблицы gdt для всех cpu для cpu0 Code:
для cpu1 Code:
Видно, что таблицы одинаковы только наполовину. Для селектора fs=30 базы разные: на cpu0 база fs - 0xFFDFF000, cpu1 - 0xF78D0000. Посмотрим что по этим адресам для cpu0 Code:
для cpu1 Code:
Таблицы адресов nt-функций в ядре, которым передается управление через int 2e или sysenter находятся по адресу [fs:[124] + E0]. По fs:[124] структура, о которой пока имею мало представления, только некоторые адреса. На cpu0 ее адрес 0x857C2448, cpu1 - 0x85266A90. Структуры для разных cpu имеют также разные адреса Для cpu0 Code:
для cpu1 Code:
Адреса структур, содержащих таблицы для разных cpu тоже разные. Для cpu0 Code:
Для cpu1 Code:
Вот здесь уже рождается вопрос. Для всех функций от 0 до 0x11C все в порядке, их таблицы даже одинаковые. 0x804E48B0 - таблица адресов функций, в основном содержит адреса в той же ntoskrnl, если только некоторые функции не перехватывается драйверами, такими vax347b (от Alcohol 120%), syser и hardlock(hasp-эмуль). 0x11C - число функций. 0x805110CC - таблица числа аргументов функции. Но для gdi, где номера функций от 0x1000 до 0x129B таблицы указаны только для cpu1!!! Бьюсь над загадкой, как это может корректно работать... Что попутно заметил, кроме подмены адресов функций, таблицы можно расширить, а также есть место для еще 2-х. Но это, возможно, будет тема следующего поста... ----- IZ.RU |
|
Создано: 15 июля 2010 17:51 · Личное сообщение · #2 |
|
Создано: 15 июля 2010 21:09 · Личное сообщение · #3 В kernel debugging mode при нормальной работе системы адрес структур с таблиц один для обоих cpu. Только на момент краша были проблемы с этим. Видимо, cpu0 уже не собирался в какой-то момент (перед крашем или во время) работать с юзермодом. Clerk, ладно стебатсья , для начинающих ядерщиков будет полезно. ----- IZ.RU |
|
Создано: 16 июля 2010 04:27 · Поправил: DenCoder · Личное сообщение · #4 Раз уж начал эту тему, несколько вопросов по теме: 1) Как узнать, на каком проце выполняется поток в kernel mode? Что-то наводит на мысль, что через fs:[0x130]. Там 0 и 1... Хотя заметил еще fs:[0x48] и fs:[0x134], там 1 и 2. 2) То же самое в user mode на WinXP x86. Возможно ли в это вообще? В MSDN нашел только GetCurrentProcessorNumber для висты. 3) Как узнать контекст другого cpu? Можно ли это? Где можно об этом прочесть? ____________________________ На первые 2 вопроса уже нашел ответ (точнее 2 вопроса объединяются в один для Intel), покопавшись в pdf'ах у себя. cpuid с eax = 1 дает в старшем байте регистра ebx номер текушего cpu, который правильно называют Local APIC ID. (Зубков ничего об этом не писал) Думаю, это оно, но боюсь, что только для Intel. Есть какой-нить универсальный способ? ____________________________ Как вариант ответа на 3 вопрос для Intel нашел способ через ICR (Interrupt Command Register), который доступен программно и позволяет из процессора в процессор посылать прерывания (IPIs). Любое незадействованное прерывание можно под это заюзать, я думаю. Только что-то геморно... ----- IZ.RU |
|
Создано: 16 июля 2010 06:12 · Личное сообщение · #5 DenCoder пишет: 1) Как узнать, на каком проце выполняется поток в kernel mode? KeGetCurrentProcessorNumber, но делать это имеет смысл только на DISPATCH_LEVEL и выше. DenCoder пишет: 2) То же самое в user mode на WinXP x86. Никак, если поток не привязан к конкретному процессору, то с тем же успехом можно узнавать через rand DenCoder пишет: 3) Как узнать контекст другого cpu? Можно ли это? Контексты есть у потоков, в ядре ещё есть KTRAP_FRAME. Контекст юзермодных потоков можно узнать через апи, ядерных - никак (документированными средствами). DenCoder пишет: cpuid с eax = 1 дает в старшем байте регистра ebx номер текушего cpu, который правильно называют Local APIC ID. Может некорректно работать на виртуальных машинах использующих программную виртуализацию. ----- PGP key |
|
Создано: 16 июля 2010 06:25 · Личное сообщение · #6 |
|
Создано: 16 июля 2010 15:51 · Личное сообщение · #7 DenCoder пишет: 2) То же самое в user mode на WinXP x86. Возможно ли в это вообще? В MSDN нашел только GetCurrentProcessorNumber для висты. Для процесса - GetProcessAffinityMask() msdn.microsoft.com/en-us/library/ms683213%28v=VS.85%29.aspx Для потока - можно через SetThreadAffinityMask(), она возвращает предыдущее значение. msdn.microsoft.com/en-us/library/ms686247%28VS.85%29.aspx Т.е. через GetProcessAffinityMask() узнать SystemAffinityMask Выполнить Code:
|
|
Создано: 17 июля 2010 01:51 · Личное сообщение · #8 cppasm Не, GetProcessAfinityMask может дать различные результаты, в том числе и переменные для одного и того же потока, если не устанавливать самому. Потом она возвращает маску процессоров, на которых могут выполняться потоки процессора, и эта маска - подмножетво из SystemAffinityMask. То же самое и с SetThreadAffinityMask. cpuid вполне подходит, если не брать в расчет некоторые виртуалки. Для amd та же команда, только с другой трактовкой регистров. ntldr KeGetCurrentProcessorNumber нету на XP. ----- IZ.RU |
|
Создано: 17 июля 2010 02:10 · Поправил: only · Личное сообщение · #9 DenCoder пишет: KeGetCurrentProcessorNumber нету на XP. ntddk.h Code:
|
|
Создано: 17 июля 2010 02:42 · Поправил: DenCoder · Личное сообщение · #10 |
|
Создано: 17 июля 2010 03:29 · Поправил: only · Личное сообщение · #11 FORCEINLINE такое встречается достаточно часто, в одних версиях ОС sdk функция в виде макроса, либо встраиваемая, в других - в экспорте (примеры: NtCurrentTeb(), ndis (там наверное десятки таких функций, которые были макросами вызова метода объекта через колбек в структуре, а стали экспортируемыми функциями)) DenCoder пишет: В MSDN нашел только GetCurrentProcessorNumber для висты. это все тот же lapic id, только, как уже сказали выше, какой с этих данных толк на PASSIVE_LEVEL не ясно |
|
Создано: 17 июля 2010 04:37 · Личное сообщение · #12 DenCoder пишет: KeGetCurrentProcessorNumber нету на XP. Всё везде есть. Это макрос DDK, смотри ntddk.h ----- PGP key |
|
Создано: 17 июля 2010 19:52 · Поправил: DenCoder · Личное сообщение · #13 only пишет: какой с этих данных толк на PASSIVE_LEVEL не ясно Раз уж дело еще и за иписами, то и от DISPATCH тоже никакого толку... Разве нельзя KeRaiseIrql использовать? Дрову буду писать потихоньку. Впервые в своей жизни, поэтому пока информацию собираю. Пока ничего серьезного, просто несколько экспериментов. ----- IZ.RU |
|
Создано: 19 июля 2010 04:38 · Личное сообщение · #14 |
|
Создано: 20 июля 2010 17:34 · Поправил: Clerk · Личное сообщение · #15 only Ядро вызывает хэндлер IPI на всех процессорах последовательно на IPI_LEVEL. Незачем реализовать самостоятельно. Хал экспортирует нужный но немного урезанный функционал. Ядро имеет функции KeIpiGenericCall/KiIpiGenericCall, первая экспортируется в старших версиях системы, но может быть найдена самостоятельно На виртеке ктото вылаживал самодостаточный код, реализующий доставку IPI. DenCoder > Разве нельзя KeRaiseIrql использовать? Можно, но это только вас ограничит. Понижать IRQL ниже текущего уровня запрещено. |
|
Создано: 21 июля 2010 03:21 · Личное сообщение · #16 |
|
Создано: 21 июля 2010 06:52 · Личное сообщение · #17 |
eXeL@B —› Программирование —› Работа ядра на 2-х и более ядрах |