Надо для одной любительской оськи (работает в реалмоде x86) написать собственные обработчики прерываний, ну и вот стал я писать такую штуку(перопределяю обработчик прерывания от клавиатуры): oldintaddr = SetIntVect(0x09, Interrupt); unsigned long SetIntVect(int no, void(*foo)(void)) - устанавливает новый обработчик прерывания. Ну это работает. Обработчик устанавливается, но потом, после выполнения своих дел он должен вызвать исходный обработчик, поэтому я поступаю так: void Interrupt() { asm("addl $8, %esp"); asm("popl %ebp"); // это всё издержки написания на си и ещё так коряво как я PutChar("."); asm("movl _oldintaddr, %eax"); asm("pushl %eax"); asm("retf"); } Тогда код нового обработчика получается такой: _Interrupt: push long ebp mov long ebp, esp sub long esp, 8 add long esp, 8 pop long ebp sub long esp, 12 push long LC8 call _PutString add long esp, 16 mov long eax, [_oldintaddr] push long eax retf mov esp, ebp pop ebp ret Убрав лишние команды, посути имеем, что мой обработчик делает: _Interrupt: sub long esp, 12 push long LC8 call _PutString add long esp, 16 ;вывод строки mov long eax, [_oldintaddr] push long eax retf В итоге, при нажатии на клавишу, действительно запускается мой обработчик, но на экране появляется не одно сообщение от PutString, а где то штук сто и всё... зависание. Правда VMWare работает, 100% грузит процессор. То есть там как то с возвратом из прерывания не так что то. Но я не пойму что. Конечно, это я скорее буду писать не на си, а на асме сразу, просто поначалу не стал заморачиваться... На сколько мне известно, при вызове прерывания сохраняются cs, ip и флаги - как это в стеке сохраняется, в каком порядке? И что я делаю не так? Рад любым подсказкам и советам.
Ой, тут я когда писал, опечатался в Interrupt. Там должно быть asm("movl [_oldintaddr], %eax"), а не asm("movl _oldintaddr, %eax"); Но это ни чего не меняет. Эффект тот же Я не пойму в чём дело.
И вот ещё: в переменной unsigned long oldintaddr - лежит, распечатывал, именно старый адрес обработчика, но, когда в Interrupt делаю такую вещь: asm("movl [_oldintaddr], %eax"); asm("pushl %eax"); asm("movl $0x78563412, %eax"); asm("pushl %eax"); asm("call _Halt"); И смотрю стэк: 12 34 56 78-00 00 00 00-E2 22 6C EC-02 02 00 00-35 20 08 20-72 FF 20 00....... То есть почему то лежит 0? Или я чего то не понимаю.
И вот ещё: в переменной unsigned long oldintaddr - лежит, распечатывал, именно старый адрес обработчика, но, когда в Interrupt делаю такую вещь: asm("movl [_oldintaddr], %eax"); asm("pushl %eax"); asm("movl $0x78563412, %eax"); asm("pushl %eax"); asm("call _Halt"); И смотрю стэк: 12 34 56 78-00 00 00 00-E2 22 6C EC-02 02 00 00-35 20 08 20-72 FF 20 00....... То есть почему то лежит 0? Или я чего то не понимаю.
Я уже ближе к разгадке, но всё равно не понятно... Делаю там сразу, без _oldintaddr: asm("movl $0xF000E987, %eax"); asm("pushl %eax"); asm("retf"); Имею при нажатии на кнопки например qwerty на экране: .q..w..e..r..t..y. - Почему окаймление с двух сторон, если PutString("."); Должен давать .q.w.e.r.t.y - и ещё с флагами, они у меня точно сохраняются, как это проще проверить? (И всё таки надо туда _oldintaddr писать, а не в ручную. Помогите советом)
я в сях не силен, но опираясь на память и школьные паскалевские годы, вроде бы сначала надо получить вектор вызвав oldintaddr=GetIntVect(...), и только потом ставить SetIntVect А сдвух сторон, потому что прерывание срабатывает при нажатии и отпускании батона
Если бы это был Дос, то тогда да... а то это соовсем левая ось. За то, что "А сдвух сторон, потому что прерывание срабатывает при нажатии и отпускании батона" - большое спасибо. Остаётся единственный вопрос, почему у меня в eax не запихивается старый адрес - это постом выше. То есть я почти разобрался. А как отличить нажатие и отпускание кнопки, там какой нить сканкод хитрый посылается?
Тут, понимаешь GetIntVect - некорректное название - он же и устаналивает новый адрес, он же и возвращает старый... Правда там надо будет коегде сделать cli/sti.... А то что то мне не нравится его устройство.
если я только не путаю, ох как давно это было, то какой-то код отпускания или нажатия на 80h больше... и в отладцике посмотри переменная _oldintaddr вообще что нибудь содержит?
ага, спасибо. Да, я после установки прерывания нового - пишу отладочную печать oldintaddr - вроде тот адрес храниться, который соответствует обработчику этого 9го прерывания. По крайней мере не 0
Это надо твой код смотреть смотреть, пока мое(да думаю и не только мое) мышение не настолько развито, что бы по 3-м строчкам кода увидеть всю картину в динамике...
Ну ладно, спасибо и за то, что сказал. Какой код ты бы хотел увидеть? Просто, вот тут _Interrupt: sub long esp, 12 push long LC8 call _PutString add long esp, 16 ;вывод строки mov long eax, [_oldintaddr] push long eax retf не передаётся в eax _oldintaddr, хотя должен. А в стеке ноль Это действительно не просто понять человеку, со стороны. Придётся мне уж самому разбираться, наверное.
Ну, здесь сделав необходимые мне действия я передаю управление старому обработчику прерывания, а для этого надо дальний вызов - запихиваю в стек сегмент:смещение и retf. А iret будет делаться но уже этим старым обработчиком прерывания. Он то вернёт уже в программу управление, и восстановит флаги ( вроде должен восстановить). Вот если бы я вообще не вызывал старый обработчик, то тогда бы мне пришлось делать iret.
Ну для начала ты киляешь содержимое eax (ax) в своем обработчике - пиши сразу jmp dword ptr _old_hanler. Также проверь, что после push eax в стек попадает CS:IP в нужном порядке (для retf).