Сейчас на форуме: tyns777 (+4 невидимых)

 eXeL@B —› Программирование —› Работа ядра на 2-х и более ядрах
Посл.ответ Сообщение


Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 15 июля 2010 14:45 · Поправил: DenCoder
· Личное сообщение · #1

Недавно, при исследовании креш-дампа, случайно обнаружил, что на разных ядрах регистры gdtr и idtr разные. Это привлекло мое внимание и быстро обнаружилась одна проблема - gdi-функции работают только на одном ядре???

По порядку. Для начала введем в WinDbg команды, чтобы узнать на момент краша содержимое регистров на всех cpu.

Для cpu0
Code:
  1. 0: kd> 0rM 0x1A9
  2. eax=ffdff13c ebx=85817ca0 ecx=00000000 edx=00000000 esi=f79a93a4 edi=85710108
  3. eip=8053767a esp=a9faab8c ebp=a9faaba4 iopl=0         nv up ei ng nz na pe nc
  4. cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000286
  5. cr0=8001003b cr2=c4d400dc cr3=06840000
  6. dr0=00000000 dr1=00000000 dr2=00000000
  7. dr3=8000f800 dr6=ffff0ff0 dr7=00000400 cr4=000006d9
  8. gdtr=8003f000   gdtl=03ff idtr=8003f400   idtl=07ff tr=0028  ldtr=0000


для cpu1
Code:
  1. 0: kd> 1rM 0x1A9
  2. eax=00000000 ebx=006cff03 ecx=006cfec0 edx=000000c0 esi=85edf000 edi=006cff61
  3. eip=bf33d6fa esp=a9778b84 ebp=e24a83f0 iopl=0         nv up ei pl zr na pe nc
  4. cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000246
  5. cr0=8001003b cr2=c4d405ab cr3=30352000
  6. dr0=00000000 dr1=00000000 dr2=00000000
  7. dr3=00000000 dr6=ffff0ff0 dr7=00000400 cr4=000006d9
  8. gdtr=f78d4160   gdtl=03ff idtr=f78d4560   idtl=07ff tr=0028  ldtr=0000


Посмотрим таблицы gdt для всех cpu

для cpu0
Code:
  1. 0: kd> dd 8003f000
  2. 8003f000  00000000 00000000 0000ffff 00cf9b00
  3. 8003f010  0000ffff 00cf9300 0000ffff 00cffb00
  4. 8003f020  0000ffff 00cff300 200020ab 80008b04
  5. 8003f030  f0000001 ffc093df 00000fff 0040f300
  6. 8003f040  0400ffff 0000f200 00000000 00000000
  7. 8003f050  77000068 80008955 77680068 80008955
  8. 8003f060  2f40ffff 00009302 80003fff 0000920b
  9. 8003f070  700003ff ff0092ff 0000ffff 80009a40


для cpu1
Code:
  1. 0: kd> dd f78d4160
  2. f78d4160  00000000 00000000 0000ffff 00cf9b00
  3. f78d4170  0000ffff 00cf9300 0000ffff 00cffb00
  4. f78d4180  0000ffff 00cff300 0d7020ab f7008b8d
  5. f78d4190  00000001 f7c0938d 80000fff 7f40f3fa
  6. f78d41a0  0400ffff 0000f200 00000000 00000000
  7. f78d41b0  30800068 f700898d 30f00068 f700898d
  8. f78d41c0  2f40ffff 00009302 80003fff 0000920b
  9. f78d41d0  700003ff ff0092ff 0000ffff 80009a40


Видно, что таблицы одинаковы только наполовину. Для селектора fs=30 базы разные: на cpu0 база fs - 0xFFDFF000, cpu1 - 0xF78D0000. Посмотрим что по этим адресам

для cpu0
Code:
  1. 0: kd> dd ffdff000 ffdff17f
  2. ffdff000  a9faadcc a9faadf0 a9fa8000 00000000
  3. ffdff010  00000000 00000000 00000000 ffdff000
  4. ffdff020  ffdff120 00000000 00000000 00000000
  5. ffdff030  ffffffff 805532b8 8003f400 8003f000
  6. ffdff040  80042000 00010001 00000001 00000a28
  7. ffdff050  00000000 00000000 00000000 00000000
  8. ffdff060  00000000 00000000 00000000 00000000
  9. ffdff070  00000000 00000000 00000000 00000000
  10. ffdff080  00000000 00000000 00000000 00000000
  11. ffdff090  00000000 00000000 0bebc200 00000000
  12. ffdff0a0  0bebc200 9af94f30 00000000 13603cce
  13. ffdff0b0  00000000 00000000 00000000 00000000
  14. ffdff0c0  00000000 00000000 00000000 00000000
  15. ffdff0d0  00000000 00000000 00000000 00000000
  16. ffdff0e0  00000000 00000000 00000000 00000000
  17. ffdff0f0  00000000 00000000 00000000 00000000
  18. ffdff100  00000000 00000000 00000000 00000000
  19. ffdff110  00000000 00000000 00000000 00000000
  20. ffdff120  00010001 857c2448 00000000 80561cc0
  21. ffdff130  00000000 00000001 170a0106 00000000
  22. ffdff140  00000000 00000000 00000000 00000000
  23. ffdff150  00000000 00000000 00000000 00000000
  24. ffdff160  00000000 00000000 00000000 00000000
  25. ffdff170  00000000 00000000 00000000 00000000


для cpu1
Code:
  1. 0: kd> dd f78d0000 f78d017f
  2. f78d0000  ffffffff a9778df0 a9775000 00000000
  3. f78d0010  00000000 00000000 7ffa8000 f78d0000
  4. f78d0020  f78d0120 00000000 00000000 00000000
  5. f78d0030  ffffffff 00000000 f78d4560 f78d4160
  6. f78d0040  f78d0d70 00010001 00000002 00000a28
  7. f78d0050  00000100 00000000 00000000 00000000
  8. f78d0060  00000000 00000000 00000000 00000000
  9. f78d0070  00000000 00000000 00000000 00000000
  10. f78d0080  00000000 00000000 00000000 00000000
  11. f78d0090  00000000 00000201 0bebc200 00000000
  12. f78d00a0  0bebc200 9af94f30 00000000 13603cce
  13. f78d00b0  00000000 00000000 00000000 00000000
  14. f78d00c0  00000000 00000000 00000000 00000000
  15. f78d00d0  00000000 00000000 00000000 00000000
  16. f78d00e0  00000000 00000000 00000000 00000000
  17. f78d00f0  00000000 00000000 00000000 00000000
  18. f78d0100  00000000 00000000 00000000 00000000
  19. f78d0110  00000000 00000000 00000000 00000000
  20. f78d0120  00010001 85266a90 00000000 f78d2e20
  21. f78d0130  00000001 00000002 170a0106 00010017
  22. f78d0140  00000000 00000000 00000000 00000000
  23. f78d0150  00000000 00000000 00000000 00000000
  24. f78d0160  00000000 00000000 00000000 00000000
  25. f78d0170  00000000 00000000 00000000 00000000


Таблицы адресов nt-функций в ядре, которым передается управление через int 2e или sysenter находятся по адресу [fs:[124] + E0]. По fs:[124] структура, о которой пока имею мало представления, только некоторые адреса. На cpu0 ее адрес 0x857C2448, cpu1 - 0x85266A90. Структуры для разных cpu имеют также разные адреса

Для cpu0
Code:
  1. 0: kd> dd 857c2448 857c2547
  2. 857c2448  00700006 00000000 857c2450 857c2450
  3. 857c2458  857c2458 857c2458 a9fab000 a9fa8000
  4. 857c2468  00000000 00000000 a9faa85c 00000200
  5. 857c2478  0e000a00 857c247c 857c247c 857c2484
  6. 857c2488  857c2484 863c4830 00000000 000003b4
  7. 857c2498  00000000 00000000 00000000 857c24b8
  8. 857c24a8  00000000 f7a6beb8 00002aa9 0400100d
  9. 857c24b8  856ba3c8 856ba3c8 857c2448 856ba3c0
  10. 857c24c8  857c24b8 00010000 00000000 00000000
  11. 857c24d8  857c2448 00000000 00000000 00000000
  12. 857c24e8  00000000 00000000 857c2448 00000000
  13. 857c24f8  00000000 00000000 857c2540 857c2540
  14. 857c2508  857c2448 857c2538 857c24b8 00010102
  15. 857c2518  00000000 00000000 00000003 00000000
  16. 857c2528  80562520 8056a5c0 00000000 00000000
  17. 857c2538  000a0008 00000000 857c2540 857c2540


для cpu1
Code:
  1. 0: kd> dd 85266a90 85266b8f
  2. 85266a90  00700006 00000000 85266a98 85266a98
  3. 85266aa0  85266aa0 85266aa0 a9779000 a9775000
  4. 85266ab0  7ffa8000 00000000 a9778acc 00000200
  5. 85266ac0  08000a00 85266ac4 85266ac4 85266acc
  6. 85266ad0  85266acc 852d9020 00000000 0000008a
  7. 85266ae0  00000000 00000000 00000002 85266b00
  8. 85266af0  80562de0 80562de0 00002aa6 09001008
  9. 85266b00  852f0488 852f0488 85266a90 861d2c28
  10. 85266b10  85266b48 00010000 851bcab8 851bcab8
  11. 85266b20  85266a90 851bcab0 85266b00 00010001
  12. 85266b30  00000000 00000000 85266a90 00000000
  13. 85266b40  00000000 00000000 85266b88 85266b88
  14. 85266b50  85266a90 85266b80 85266b00 00010102
  15. 85266b60  00000000 fffffffc 00000003 00000000
  16. 85266b70  805624e0 00000000 00000000 00000000
  17. 85266b80  000a0008 00000000 85266b48 85266b48


Адреса структур, содержащих таблицы для разных cpu тоже разные.

Для cpu0
Code:
  1. 0: kd> dd 80562520 8056255f
  2. 80562520  804e48b0 00000000 0000011c 805110cc
  3. 80562530  00000000 00000000 00000000 00000000
  4. 80562540  00000000 00000000 00000000 00000000
  5. 80562550  00000000 00000000 00000000 00000000


Для cpu1
Code:
  1. 0: kd> dd 805624e0 8056251f
  2. 805624e0  804e48b0 00000000 0000011c 805110cc
  3. 805624f0  bf99a200 00000000 0000029b bf99af10
  4. 80562500  00000000 00000000 00000000 00000000
  5. 80562510  00000000 00000000 00000000 00000000


Вот здесь уже рождается вопрос. Для всех функций от 0 до 0x11C все в порядке, их таблицы даже одинаковые. 0x804E48B0 - таблица адресов функций, в основном содержит адреса в той же ntoskrnl, если только некоторые функции не перехватывается драйверами, такими vax347b (от Alcohol 120%), syser и hardlock(hasp-эмуль). 0x11C - число функций. 0x805110CC - таблица числа аргументов функции. Но для gdi, где номера функций от 0x1000 до 0x129B таблицы указаны только для cpu1!!! Бьюсь над загадкой, как это может корректно работать...

Что попутно заметил, кроме подмены адресов функций, таблицы можно расширить, а также есть место для еще 2-х. Но это, возможно, будет тема следующего поста...

-----
IZ.RU




Ранг: 255.8 (наставник), 19thx
Активность: 0.150.01
Статус: Участник
vx

Создано: 15 июля 2010 17:51
· Личное сообщение · #2

DenCoder
> обнаружил, что на разных ядрах регистры gdtr и idtr разные.
ы и после таких вопросов вы есчо пытались со мной чемто меряться
Каждый процессор имеет сою уникальную среду, это PCR, GDT, IDT, DPC-stack etc.)




Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 15 июля 2010 21:09
· Личное сообщение · #3

В kernel debugging mode при нормальной работе системы адрес структур с таблиц один для обоих cpu. Только на момент краша были проблемы с этим. Видимо, cpu0 уже не собирался в какой-то момент (перед крашем или во время) работать с юзермодом.

Clerk, ладно стебатсья , для начинающих ядерщиков будет полезно.

-----
IZ.RU





Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 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




Ранг: 369.8 (мудрец), 400thx
Активность: 0.390
Статус: Участник

Создано: 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 <0x1B6A24550F33E44A>




Ранг: 2.4 (гость)
Активность: 0=0
Статус: Участник

Создано: 16 июля 2010 06:25
· Личное сообщение · #6

может стоит уже в windbg сделать dt nt!_KPCR и посмотреть что там есть, а не спрашивать по смещениям ^___^?



Ранг: 251.3 (наставник), 81thx
Активность: 0.140.11
Статус: Участник

Создано: 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:
  1. PrevThreadAffinityMask=SetThreadAffinityMask(hThread, SystemAffinityMask); // Разрешить запуск на всех CPU
  2. SetThreadAffinityMask(hThread, PrevThreadAffinityMask); // Восстановить маску
  3. Sleep(0); // Перепланировать поток, если изменения в планировании потока не критичны, можно не делать





Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 17 июля 2010 01:51
· Личное сообщение · #8

cppasm
Не, GetProcessAfinityMask может дать различные результаты, в том числе и переменные для одного и того же потока, если не устанавливать самому. Потом она возвращает маску процессоров, на которых могут выполняться потоки процессора, и эта маска - подмножетво из SystemAffinityMask. То же самое и с SetThreadAffinityMask.

cpuid вполне подходит, если не брать в расчет некоторые виртуалки. Для amd та же команда, только с другой трактовкой регистров.

ntldr
KeGetCurrentProcessorNumber нету на XP.

-----
IZ.RU




Ранг: 0.4 (гость)
Активность: 0=0
Статус: Участник

Создано: 17 июля 2010 02:10 · Поправил: only
· Личное сообщение · #9

DenCoder пишет:
KeGetCurrentProcessorNumber нету на XP.


ntddk.h
Code:
  1. //
  2. // Get the current processor number
  3. //
  4.  
  5. =-> FORCEINLINE <-=
  6. ULONG
  7. NTAPI
  8. KeGetCurrentProcessorNumber(VOID)
  9. {
  10. #if (_MSC_FULL_VER >= 13012035)
  11.     return (ULONG) __readfsbyte (FIELD_OFFSET (KPCR, Number));
  12. #else
  13.     __asm {  movzx eax, _PCR KPCR.Number  }
  14. #endif
  15. }
  16.  





Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 17 июля 2010 02:42 · Поправил: DenCoder
· Личное сообщение · #10

only
Среди экспорта такой функи не обнаружено

-----
IZ.RU




Ранг: 0.4 (гость)
Активность: 0=0
Статус: Участник

Создано: 17 июля 2010 03:29 · Поправил: only
· Личное сообщение · #11

FORCEINLINE
такое встречается достаточно часто, в одних версиях ОС sdk функция в виде макроса, либо встраиваемая, в других - в экспорте (примеры: NtCurrentTeb(), ndis (там наверное десятки таких функций, которые были макросами вызова метода объекта через колбек в структуре, а стали экспортируемыми функциями))
DenCoder пишет:
В MSDN нашел только GetCurrentProcessorNumber для висты.

это все тот же lapic id, только, как уже сказали выше, какой с этих данных толк на PASSIVE_LEVEL не ясно



Ранг: 369.8 (мудрец), 400thx
Активность: 0.390
Статус: Участник

Создано: 17 июля 2010 04:37
· Личное сообщение · #12

DenCoder пишет:
KeGetCurrentProcessorNumber нету на XP.

Всё везде есть. Это макрос DDK, смотри ntddk.h

-----
PGP key <0x1B6A24550F33E44A>





Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 17 июля 2010 19:52 · Поправил: DenCoder
· Личное сообщение · #13

only пишет:
какой с этих данных толк на PASSIVE_LEVEL не ясно

Раз уж дело еще и за иписами, то и от DISPATCH тоже никакого толку... Разве нельзя KeRaiseIrql использовать?

Дрову буду писать потихоньку. Впервые в своей жизни, поэтому пока информацию собираю. Пока ничего серьезного, просто несколько экспериментов.

-----
IZ.RU





Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 19 июля 2010 04:38
· Личное сообщение · #14

only
Ты 3-ий вопрос пропустил. Оттуда и IPI. Прочти про них, если не знаешь, потом говори.

-----
IZ.RU




Ранг: 255.8 (наставник), 19thx
Активность: 0.150.01
Статус: Участник
vx

Создано: 20 июля 2010 17:34 · Поправил: Clerk
· Личное сообщение · #15

only
Ядро вызывает хэндлер IPI на всех процессорах последовательно на IPI_LEVEL.
Незачем реализовать самостоятельно. Хал экспортирует нужный но немного урезанный функционал. Ядро имеет функции KeIpiGenericCall/KiIpiGenericCall, первая экспортируется в старших версиях системы, но может быть найдена самостоятельно http://files.virustech.org/indy/Code/Ipi/
На виртеке ктото вылаживал самодостаточный код, реализующий доставку IPI.
DenCoder
> Разве нельзя KeRaiseIrql использовать?
Можно, но это только вас ограничит. Понижать IRQL ниже текущего уровня запрещено.



Ранг: 61.4 (постоянный), 1thx
Активность: 0.020
Статус: Участник

Создано: 21 июля 2010 03:21
· Личное сообщение · #16

> На виртеке ктото вылаживал самодостаточный код, реализующий доставку IPI.
50 строк си кода



Ранг: 255.8 (наставник), 19thx
Активность: 0.150.01
Статус: Участник
vx

Создано: 21 июля 2010 06:52
· Личное сообщение · #17

n0name
Точно это вы были


 eXeL@B —› Программирование —› Работа ядра на 2-х и более ядрах
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати