Доброго времени суток. Я думал все современные компиляторы поддерживают полный набор команд встроенного ассемблера... gcc (v 3.4.2 может быть старая?) при попытке скомпилить код с командой iretd gcc говорит "no such instruction: 'iretd'". Что с этим делать? Или, может быть, можно как-нибудь по другому?
iretl = iretd?=) Почему-то плохо както работает, bochs пишет IRET PROTECTED exception(0x01) interrupt(): ... interrupt(): gate descriptor is not valid sys seg Как должна выглядеть процедура обработки прерывания на Си и что за 'gate descriptor is not valid sys seg'?
Vilco Глобальные вопросы, скажем прямо. Процедура обработки прерывания, в принципе, не отличается от обычной процедуры. Разве что 'iret' в конце стоит. Дальше все зависит от того, что ты делаешь. Возможно, необходимо сохранить регистры, чтобы обработчик их не испортил, возможно, необходимо вытолкнуть из стека код ошибки, возможно послать EOI контроллеру прерываний. В общем, опиши более подробно, что тебе требуется. Bochs, по-видимому ругается на дескриптор в IDT. Скорее всего на тип дескриптора. В IDT могут жить лишь шлюзы ловушек, шлюзы прерываний и шлюзы задач. Чтобы сказать точнее надо увидеть код.
да, синтаксис AT&T имхо, первичный обработчик нужно писать на ассемблере, а уж из него вызывать процедуру на С скорее всего компилятор генерирует Код (Text): push ebp mov ebp, esp в начале твоего обработчика, а iretd вызывается до pop ebp т. е Код (Text): void handler() { __asm__("iretl") } Код (Text): handler: pushl %ebp movl %esp, %ebp iretl popl %ebp ret
Хм, Дело на 99% не в этом. Потому что до замены адреса обработчика (2 первых и 2 последних байта вроде) дескриптор нормально, корректно функционировал. Как только я ставлю туда си-процедуру - бред какой-то получается. Похоже так оно и есть=( Я натравил на бинарник еду, пролог действительно есть, а эпилог получается за iret. Получается что нужно просто вручную вытащить ebp из стека и остальное оставить как есть? Ах да, про interrupt где почитать?) Спасибо
http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Function-Attributes.html#Function-Attributes но этот атрибут не для x86
Вроде разобрался, но как-то коряво получается. Самому приходится стек чистить от временных переменных - каждый раз смотреть чё он там скомпилил(. Если ли какой-нибудь аналог __declspec(naked) в gcc? Как нить его можно включить (а то по ссылке в списке тоже не вижу x86, а при попытке вставить гцц пишет 'naked' attribute directive ignored)?
По-моему, это не то совсем... Описание говорит об этом, но я на всякий случай воткнул атрибут pure, компилер съел, а пролог-эпилог так и остался... Ладно пойду асм воткну... Edited: всем спасибо, можно закрывать. С помощью си так и не получилось на gcc сделать...
Та же проблема... Действовал согласно http://wiki.osdev.org/Interrupt_Service_Routines получилось такое: Код (Text): .globl int_timer int_timer: pushal call _int_timer popal iret bochs пишет следущее Код (Text): 00013627163e[DEV ] write to port 0x0007 with len 4 ignored 00013627169i[CPU0 ] BxError: instruction with opcode=0xff 00013627169i[CPU0 ] mod was c0, nnn was 7, rm was 7 00013627169i[CPU0 ] WARNING: Encountered an unknown instruction (signalling illegal instruction) 00013627169e[CPU0 ] interrupt(): gate descriptor is not valid sys seg 00013627169e[CPU0 ] interrupt(): gate descriptor is not valid sys seg 00013627169i[CPU0 ] protected mode 00013627169i[CPU0 ] CS.d_b = 32 bit 00013627169i[CPU0 ] SS.d_b = 32 bit 00013627169i[CPU0 ] | EAX=00100800 EBX=0002cea0 ECX=0000000c EDX=0010004f 00013627169i[CPU0 ] | ESP=001ffff8 EBP=00067eac ESI=00053b25 EDI=00053b2a 00013627169i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df IF tf sf zf af pf cf 00013627169i[CPU0 ] | SEG selector base limit G D 00013627169i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D 00013627169i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1 00013627169i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1 00013627169i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1 00013627169i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1 00013627169i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1 00013627169i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1 00013627169i[CPU0 ] | EIP=0002ceac (0002ceac) 00013627169i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000 00013627169i[CPU0 ] | CR3=0x00000000 CR4=0x00000000 00013627169i[CPU0 ] >> (invalid) : FFFF 00013627169e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting EIP=0002ceac - я так понял, шо раз он сюда попал то при выходе из прерывания eip содержал неправильное значение...
А можно IDT/GDT увидеть? Как я понял из лога, происходит исключение 6 (#UD), а обработчики не настроены.
Код (Text): exception(): 3rd (13) exception] с IDT и GDT все в порядке, если код изменить так: Код (Text): pushal popal hlt iret или внутри функции _int_timer поставить for(;; то все работает, как и должно...
Код (Text): 00013627163e[DEV ] write to port 0x0007 with len 4 ignored 00013627169i[CPU0 ] BxError: instruction with opcode=0xff <--Началось все здесь. 00013627169i[CPU0 ] mod was c0, nnn was 7, rm was 7 00013627169i[CPU0 ] WARNING: Encountered an unknown instruction (signalling illegal instruction) <--Bochs понял, что с инструкцией беда. 00013627169e[CPU0 ] interrupt(): gate descriptor is not valid sys seg <--Продолжение банкета. 00013627169e[CPU0 ] interrupt(): gate descriptor is not valid sys seg IDT можно посмотреть командой info idt. И раз используется Bochs, почему бы не посмотреть по шагам что происходит? Либо код покажите.
IDT не виновато... Но все же: Код (Text): void __idt::edit(unsigned char vector,void (*func)(void), unsigned char type) { unsigned char* idt_table=(unsigned char*)IDT_TABLE; unsigned char rec[8]; rec[0]=(unsigned int)func & 0xFF; rec[1]=((unsigned int)func & 0xFF00)>>8; rec[2]=SYS_CODE_SELECTOR; rec[3]=0; rec[4]=0; rec[5]=type; rec[6]=((unsigned int)func & 0xFF0000)>>16; rec[7]=((unsigned int)func & 0xFF000000)>>24; for(int i=0;i<8;*((unsigned char*)(IDT_TABLE+vector*8+i))=rec[i++]); } Код (Text): edit(0x8,&int_timer,0x8E); Проблема в том, шо он начал исполнять инструкцию по адресу 0002ceac, туда он не должен попадать. Ядро заканчивается гораздо раньше.