Может у кого есть ссылка на пример кода, отлавливающего обращение к портам под DOS, или что то почитать на эту тему?
Установка брекпойнтов на I/O действительно обламывается. Не совсем понятно зачем обнулять DRx. При установленном GD в DR7 такой код все равно сгенерит отладочное исключение. Имхо, в RM проще перехватить int 1 и в своем обработчике делать с DRx что в голову придет
Установка брекпойнтов на I/O действительно обламывается. Не совсем понятно зачем обнулять DRx. При установленном GD в DR7 такой код все равно сгенерит отладочное исключение. Имхо, в RM проще перехватить int 1 и в своем обработчике делать с DRx что в голову придет
Огромное спасибо, Chingachguk ! Но, как всегда, есть еще один вопрос: У меня бряк на порт срабатывает после записи в порт (сделал TSR, и при нажатии на клавишу, сначала загорается лампочка в LPT, а потом срабатывает обработчик). Значит, запись в порт происходит до попадания в обработчик. А как же мне тогда запретить запись в порт? В обработчике находится hlt, так что после загорания диода все виснет (так я определяю до или после обработчика происходит запись в порт).
В RM никак. Остается только сожалеть, что бряки на r/w работают после выполнения инструкции, вызвавшей исключение. З.Ы. Честно говоря, всегда вызывало недоумение такое решение интеловцев. Видимо реализация бряков до исполнения инструкции здорово повлияла бы на perfomance. ИМХО
Обидно Это означает что в PM можно? В чем тогда отличие? А в RM совсем-совсем никак (может другим способом)?
Действительно, здесь (http://www.intel.com/design/pentiumii/manuals/243192.htm Chapter 15.3.1.2) написано, что Там же и про SMM есть. Интересно, если использовать SMM, то SMI будет генерироватся до или после обращения к порту? Так в этой ветке http://www.wasm.ru/forum/viewtopic.php?id=8842&p=2 _BC_ написал, что Если сайс использует отладочныеt регистры, значит исключение (сайс) происходит сразу после обращения к порту. Получается, что обработчик SMI получит управление перед записью в порт?
Здесь что, совсем никого нет? Уже полностью разобрался как открыть, закрыть SMRAM и записать/прочитать что-нибудь туда (очень помогли архивы _BC_). Смещение для SMRAM Control Register у меня (430VX) равное 72h. Удачно сдампил SMRAM. В дизассемблерном дампе нашел процедуры открытия и закрытия памяти, но установить бряки на порт пока не получается. Как я понял, процедуры разрешения/запрета SMI и установки точки останова (IO_TRAP.ASM) взяты из дампа памяти. Но в моем дампе таких процедур нет, или я их еще не нашел. Кнопка Power у меня не обрабатывается (AT). Помогите поставить бряки с моим дампом, или хотя бы подскажите где почитать (в интеловской документации на мой чипсет про это не сказано). Помогите хоть чем-нибудь!
lukash Использование регистров отладки для этой цели не поможет, поскольку существует гарантированный перехват любого DRx приложением режима ядра. ДА ктати наиболее интересный момент, когда ставишь бряк поинт на чтение памяти в которой хранится адрес обработчика INT 1.. Но и этот случай обходится.
Если быть точным -- до завершения команды I/O. На старых процах это реализовывалось выдачей сигнала SMI# до RDY#. Ловушка же по I/O на проце срабатывает после полного завершения I/O-цикла. Нет. Chipset Intel Triton II 430VX North Bridge i82437VX South Bridge i82371SB PIIX3 Это слишком старый чипсет, на нем не то что иотрапы, на нем даже ACPI не поддерживается. лучше развивай drX -- на их основе тоже можно решать задачи не хуже при должном подходе. Можно как на 'пре-', так и на 'пост-' успешно вклиниваться в нужных местах и подменять данные, хоть и не без геморроя. Благо протокол посылки ATA-команд и данных довольно гибкий.
_BC_ А от чего зависит в какой момент будет сгенерировано исключение? Подскажите где о этом почитать.
lukash мм, ты наверное не осознаешь полностью, что значит ловить I/O в "пре-", т.е. ПЕРЕД собственно выполнением I/O. Перехват I/O на "пре" -- это не перехват int 21h, "оригинальный обработчик" тут не вызовешь. "PRE"-перехват можно организовать и на drX -- но в общем случае это chipset-specific (хотя теоретически можно на IDE-контроллере вырубать IO Enable на те промежутки, когда irq не ожидается... но это всего лишь непроверенная мысль, хоть и универсальное решение). В твоем случае с IDE, "PRE" шибко и не нужно -- если тебе надо подменять считываемые/записываемые из/в устройства данные -- то можно вклиниваться в определенные моменты и подменять данные. Например, при ATA-командах, посылающих данные в устройство, после отлова записи в command port (сразу или по отлову готовности) можно самому послать нужные данные и закончить команду с последующим игнорированием устройством посылаемых данных. Грубо, но должно работать. При чтении вообще никаких проблем.
Настроив систему на "невосприимчивость" на перехватываемых портах (в данном случае IDE) средствами чипсета, т.е. I/O-команды будут выполняться, но не доходить до устройств. Обработчик PRE восстанавливает "чувствительность" перехватываемых портов и вручную эмулирует I/O.
Вот, например, код процедуры для подачи ATA-команды: Код (Text): ; Стандартные базовые адреса каналов 1 и 2 StandardATABases DW 1F0h, 170h ; Номер канала ChannelNumber DW ? ; Номер диска DiskNumber DB ? ; Базовый адрес группы портов контроллера ATA ATABasePortAddr DW ? ; Параметры ATA-команды ATAFeatures DB ? ;особенности ATASectorCount DB ? ;количество обрабатываемых секторов ATASectorNumber DB ? ;номер начального сектора ATACylinder DW ? ;номер начального цилиндра ATAHead DB ? ;номер начальной головки ATAAddressMode DB ? ;режим адресации (0 - CHS, 1 - LBA) ATACommand DB ? ;код команды, подлежащей выполнению ; Код ошибки (0 - нет ошибок, 1 - превышен допустимый ; интервал ожидания, 2 - неверный код режима адресации, ; 3 - неверный номер канала, 4 - неверный номер диска, ; 5 - неверный номер головки, 6 - ошибка при выполнении ; команды) DevErrorCode DB ? ; Время начала очередной операции с диском OpTime DD ? ;**************************************************** ;* ПОСЛАТЬ КОМАНДУ ЗАДАННОМУ ДИСКУ * ;* Входные параметры передаются через глобальные * ;* переменные: * ;* ChannelNumber - номер канала (1 или 2); * ;* DiskNumber - номер диска (0 или 1); * ;* ATAFeatures - "особенности"; * ;* ATASectorCount - количество секторов; * ;* ATASectorNumber - номер начального сектора; * ;* ATACylinder - номер начального цилиндра; * ;* ATAHead - номер начальной головки; * ;* ATAAddressMode - режим адресации (0-CHS, 1-LBA); * ;* ATACommand - код команды. * ;* После успешного выполнения функции: * ;* в ATABasePortAddr - базовый адрес HDD; * ;* в OpTime - момент начала выполнения команды; * ;* в DevErrorCode - ноль. * ;* При возникновении ошибки в DevErrorCode будет * ;* возвращен код ошибки. * ;**************************************************** PROC SendCommandToHDD near pushad ; Запомнить время начала операции с диском ; Загрузить в ES сегмент данных BIOS mov AX,0 mov ES,AX ; Запомнить текущее время mov EAX,[ES:046Ch] mov [OpTime],EAX ; Проверить значение кода режима cmp [ATAAddressMode],1 ja @@Err2 ; Проверить корректность номера канала mov BX,[ChannelNumber] cmp BX,1 jb @@Err3 cmp BX,2 ja @@Err3 ; Установить базовый адрес dec BX shl BX,1 mov AX,[BX+StandardATABases] mov [ATABasePortAddr],AX ; Ожидание готовности HDD к приему команды ; Выбрать нужный диск mov DX,[ATABasePortAddr] add DX,6 ;адрес регистра головок mov AL,[DiskNumber] cmp AL,1 ;проверить номера диска ja @@Err4 shl AL,4 or AL,10100000b out DX,AL ; Ожидать, пока диск не будет готов inc DX @@WaitHDReady: ; Проверить время ожидания mov EAX,[ES:046Ch] sub EAX,[OpTime] cmp EAX,BSYWaitTime ja @@Err1 ;ошибка тайм-аута ; Прочитать регистр состояния in AL,DX ; Проверить состояние сигнала BSY test AL,80h jnz @@WaitHDReady ; Проверить состояние сигнала DRQ test AL,08h jnz @@WaitHDReady ; Загрузить команду в регистры контроллера mov DX,[ATABasePortAddr] inc DX ;регистр "особенностей" mov AL,[ATAFeatures] out DX,AL inc DX ;счетчик секторов mov AL,[ATASectorCount] out DX,AL inc DX ;регистр номера сектора mov AL,[ATASectorNumber] out DX,AL inc DX ;номер цилиндра (младший байт) mov AX,[ATACylinder] out DX,AL inc DX ;номер цилиндра (старший байт) mov AL,AH out DX,AL inc DX ;номер головки/номер диска mov AL,[DiskNumber] shl AL,4 cmp [ATAHead],0Fh ;проверить номер головки ja @@Err5 or AL,[ATAHead] or AL,10100000b mov AH,[ATAAddressMode] shl AH,6 or AL,AH out DX,AL ; Послать команду mov AL,[ATACommand] inc DX ;регистр команд out DX,AL ; Сбросить признак ошибки mov [DevErrorCode],0 jmp short @@End ; Записать код ошибки @@Err1: mov [DevErrorCode],1 jmp short @@End @@Err2: mov [DevErrorCode],2 jmp short @@End @@Err3: mov [DevErrorCode],3 jmp short @@End @@Err4: mov [DevErrorCode],4 jmp short @@End @@Err5: mov [DevErrorCode],5 ; Завершение работы программы @@End: popad ret ENDP SendCommandToHDD Как я понял, нужно вклинится в код до загрузки команды в регистры контроллера, проверить что это за команда, и затем, если нужно, послать команду с помощью приведенного выше кода, например. В каком месте лучше всего вклиниваться в код и как это правильно сделать. Если поставить бряк на “чтение регистра состояния”, то как я узнаю какая команда должна была передаться.
Тебе надо подменять ATA-команды без данных? Если нет -- то перехвата записи в command port достаточно и "post-".
_BC_ По моему, я немного неправильно написал: мне не нужно подменять посылаемые данные в порт, а подменять ATA команды. Мне нужно в определенный момент запретить запись в определенный сектор, или эмулировать запись. Так, например, при посылке команды 30h (Write Sector), мне нужно вклинится в код при проверке готовности устройства и запретить (эмулировать) запись. Я не очень понял где нужно вклинится и каким способом. Можно немного подробнее о "отлове записи в command port " (как перехватить запись).
Вот написал код, который, теоретически, должен вклиниваться после посылки команды. Код (Text): .386p cs16 segment use16 byte assume cs:cs16 assume ds:cs16 org 100h begin: jmp main main: push 0 pop es sub word ptr es:[0413h],2 mov ax,es:[0413h] mov cl,6 shl ax,cl mov es,ax ; копирование процедуры в память начиная с es:0000 xor si,si mov cx,prg_lenght prg_copy: mov bl,byte ptr cs:@@ResidentalCode[si] mov byte ptr es:[si],bl inc si loop cs:prg_copy cli push es pop ds mov ax,0h mov es,ax mov dx,0000h+(offset int_01 - offset @@ResidentalCode) mov es:[1h*4],dx mov es:[1h*4+2],ds sti cli mov eax,cr4 or eax,8 ;i/o breakpoints mov cr4,eax mov eax,1f6h ;ide 0 master mov dr0,eax mov eax,020703h ;enable port trace mov dr7,eax sti int 20h @@ResidentalCode: int_01 proc far ; процедура обработки int 01h pushf pusha push es push ds push 0B800h pop es mov ah,31 mov al,1 mov di,0 mov es:[di],ax cmp al,20h jnz @@Err ;команда чтения сектора mov dx,1f7h ;установка ERR в 1 mov al,1 out dx,al mov dx,3f6h ;Разрешить прерывания от устройства mov al,0 out dx,al @@Err: pop ds pop es popa popf iret int_01 ENDP RES_END: prg_lenght EQU RES_END - @@ResidentalCode cs16 ends После посылки команды в 01F6h порт (в данном случае 20h), с 01F0h порта (ide 0 master ) можно считать данные (послу проверок на готовность). Если здесь установить ERR в 1 (01F7h), то в теории считывание данных происходить не должно. Но у меня сектора читаются, правда с большой задержкой. Подскажите где ошибка.