кто мешает вызвать MmMapIoSpace() до программирования таймера т. е получить линейный адрес, отображающий страницу (0xFEE00000 - 0xFEE01000)
Ничего не получаеться При любом раскладе (MmMapIoSpace - отрабатывает отлично), когда я пытаюсь хоть как то запрограмить local APIC вылетает BSOD /* сил моих больше нет ... все выхи над этим сидел и пару дней до этого ... */
В винде есть промапленный апик, я не понял причины проблемы. Посмотрите код KfRaiseIrql для hal, где идет запись в TPR: .text:80012278 KfRaiseIrql proc near ; CODE XREF: sub_800122F8+5p .text:80012278 ; sub_80014C26+4Fp ... .text:80012278 movzx edx, cl .text:8001227B movzx ecx, ds:_HalpIRQLtoTPR[edx] .text:80012282 mov eax, ds:0FFFE0080h .text:80012287 mov ds:0FFFE0080h, ecx .text:8001228D shr eax, 4 .text:80012290 movzx eax, ds:_HalpIRQLtoTPR[eax] .text:80012297 retn .text:80012297 KfRaiseIrql endp Насколько я помню этот адрес даже вроде не меняется от версии к версии
так. всё равно не работает. пошёл по порядку: 1. есть функция призваная найти вектор для конкретного прерывания Код (Text): BYTE search_irq_vector( BYTE irqnum ) { unsigned char *pIoRegSel; unsigned char *pIoWin; BYTE ch; PHYSICAL_ADDRESS phys; PVOID pAddr; phys.QuadPart = 0xFEC00000; pAddr = MmMapIoSpace( phys, 0x1000, MmNonCached ); if( pAddr == NULL ) return 0; pIoRegSel = (unsigned char *) pAddr; pIoWin = (unsigned char *) (pAddr) + 0x10; *pIoRegSel = 0x10 + irqnum * 2; ch = *pIoWin; MmUnmapIoSpace( pAddr, 0x1000 ); return ch; } первая непонятка в том что почему то эта функция всегда возращает 0xFF, будь то IRQ0 или IRQ1, или .... далее есть структура IDT Код (Text): typedef struct _idt { WORD l_offs; WORD sel; BYTE res; union { BYTE attrs; struct { BYTE type:4; BYTE rs:1; BYTE dpl:2; BYTE p:1; }; }; WORD h_offs; } idt; далее получаю таблицу idt следующим образом: Код (Text): idt *ptable; __asm { mov eax, [ptable] sidt [eax] } и следовательно по идеи обработчик прерывания IRQ0 должен находиться в ptable[search_irq_vector( 0 )], но правильн оли это при search_irq_vector( 0 ) == 0xFF? и ещё есть вопрос по обработчику самого прерывания на данный момент он у меня выглядит следующим образом: Код (Text): __declspec( naked ) void Handler() { PHYSICAL_ADDRESS APICAddr; unsigned char * APICptr; __asm pushad; APICAddr.LowPart = 0xFEE00000; APICAddr.HighPart = 0; APICptr = (unsigned char *) MmMapIoSpace( APICAddr, 0x1000, MmNonCached ); if( APICptr != NULL ) { // тут делаем свои надобности __asm { mov eax, APICptr add eax, 0x0B0 mov ebx, 0x0 mov [eax], ebx // сообщанем APIC что мы закончили обработку прерывания } MmUnmapIoSpace( APICptr, 0x1000 ); } __asm { popad jmp [oldisr] } } всё ли я корректно делаю? ещё хоетлось бы узнать как можно MmMapIoSpace заменить на ассемблерный код, уж очень не красиво смотриться перемешка asm и С... хотелось бы что бы было всё единообразно.
У меня по началу тоже бсодило, когда устанавливал коэфициен деления 128, меньше работает. Видимо ОС использует прерывания от этого таймера для планирования(прерывание #FDh). Без MmMapIoSpace можно попробовать сборкой: записать в память код(например mov eax,dword ptr ds:[Address]), а затем записать вместо Address, виртуальный адрес регистра. Я не могу понять что делает search_irq_vector(), ищет адре обработчика прерывания по его номеру в IDT ?
Код (Text): IDTR_FIELD struct _Limit WORD ? ;Предел таблицы IDT(её размер) _Base PVOID ? ;Адрес начала IDT IDTR_FIELD ends PIDTR_FIELD typedef ptr IDTR_FIELD INTERRUPT_GATE struct ;Дескриптор шлюза прерывания в IDT OffsetLo WORD ? ;Bits 0-15 Selector WORD ? ;Bits 16-31 AccessRights WORD ? comment ' RECORD \ _Present:1, ;Bits 15 Присутствие сегмента в памяти. Если этот бит установлен, то сегмент есть в памяти, если сброшен, то его нет. _Dpl:2 ;Bits 13-14 Поле DPL (Descriptor Privilege Level) - Уровень привилегий, который имеет объект, описываемый данным дескриптором. _System:1, ;Bits 12 Бит S (System) - определяет системный объект. Если этот бит установлен, то дескриптор определяет сегмент кода или данных, а если сброшен, то системный объект (например, сегмент состояния задачи, локальную дескрипторную таблицу, шлюз). _Default_Big:1, ;Bits 11 D - это размер шлюза: 1 = 32 бита; 0 = 16 бит. _Type:3, ;Bits 8-10 [110] _Undefined1:8' OffsetHi WORD ? INTERRUPT_GATE ends PINTERRUPT_GATE typedef ptr INTERRUPT_GATE GetInterruptVector proc InterruptNumber:ULONG Local Descriptor:IDTR_FIELD ;Определяет вектор прерывания для текущего процессора. ;Не проверяет на корректность параметры. ;Вход: InterruptNumber - номер прерывания ;Выход: Eax:Вектор, Edx:Селектор, Ecx:Атрибуты cli sidt Descriptor mov eax,InterruptNumber mov edx,Descriptor._Base ;адрес IDT lea edx,[edx+eax*SizeOf INTERRUPT_GATE] assume edx:PINTERRUPT_GATE movzx eax,[edx].OffsetHi shl eax,16 movzx ecx,[edx].AccessRights or ax,[edx].OffsetLo mov dx,[edx].Selector movzx ecx,cx movzx edx,dx sti ret GetInterruptVector endp SetInterruptVector proc PrivilegeLevel:ULONG, InterruptNumber:ULONG, Vector:PVOID, Selector:ULONG Local Descriptor:IDTR_FIELD ;Устанавливает вектор прерывания для текущего процессора. ;Не проверяет на корректность параметры. cli sidt Descriptor mov eax,InterruptNumber mov edx,Descriptor._Base ;адрес IDT lea edx,[edx+eax*SizeOf INTERRUPT_GATE] assume edx:PINTERRUPT_GATE mov eax,Vector mov [edx].OffsetLo,ax shr eax,16 mov [edx].OffsetHi,ax mov eax,Selector mov [edx].Selector,ax mov eax,PrivilegeLevel mov [edx].AccessRights,1000111000000000b .if Eax or [edx].AccessRights,0110000000000000b .endif sti ret SetInterruptVector endp IsValidInterruptGate proc InterruptNumber:ULONG Local Descriptor:IDTR_FIELD ;Проверяет корректность шлюза прерывания для текущего процессора. ;Вход: InterruptNumber - номер прерывания cli mov eax,InterruptNumber sidt Descriptor lea eax,[eax*SizeOf INTERRUPT_GATE] cmp ax,Descriptor._Limit jnc error_ mov edx,Descriptor._Base ;адрес IDT lea edx,[edx+eax] assume edx:PINTERRUPT_GATE movzx eax,[edx].OffsetHi shl eax,16 or ax,[edx].OffsetLo test eax,eax jz error_ movzx edx,[edx].Selector test dx,dx jz error_ movzx eax,[edx].AccessRights test eax,1000000000000000b jz error_ test eax,0001000000000000b jnz error_ and ah,111b cmp ah,110b jz exit_ error_: xor eax,eax exit_: sti ret IsValidInterruptGate endp
в спецификации на I/O APIC по поводу Data Register написано следующее а у тебя насколько я вижу идет не 32-х разрядный доступ к нему
2rei3er Указатели дело такое(что DWORD*, что BYTE* - разница будет только в смещенгиях от начала указателя)... я завтра попробую сменить тип данных, но не думаю что это что то изменит. А может быть так что если не задан обработчик прерывания то значение будет 0xFF и нужно будет заводить самому (руками) запись в таблице?
есть какие-нибудь замечания по обработчику прерывания от local APIC timer? (ну малоли, моя грамотность может наделать и 3 ошибки в одном слове....)
тот адресс что я получаю через sidt для самой таблицы IDT, я так понимаю его нужно тоже преобразовывать через MmMapIoSpace, что бы можно было с ним работать? или нет?
нет он линейный не всегда я тоже не думаю думаю, такое вполне вероятно но не для всех же линий IRQ кстати, какой у тебя чипсет?
хм.. как вариант стоит проверить.. а это можно узнать из cpuid или каких нибудь MSR (как например адрес регистров для local APIC)? (завтра то я скорее всего найду эту информацию на работе, но если Вы её знаете может поделитесь?)