0

Я написал этот код, чтобы создать образец IDT и загрузить его в соответствующий регистр. Я проверил руководства по системному программированию Intel для правильных структур, и все же я не могу заставить прерывания работать. Во время работы кода ядра в Bochs, и вызвав прерывание (с помощью __asm__ ("int $32"); я получаю журнал, который говорит:.Столбец дескриптора прерывания

00135687199e[CPU0 ] interrupt(): gate not present 
00135687199e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0b) 
00135687199e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08) 

Конечно, это приводит к сбросу процессора, так как прерывание необработанное Для загрузки IDT я использую следующее:

extern void _lidt(_IDT_PTR* idtPtr); //C code side 
//Assembly 
.global _lidt 
_lidt: 
push %ebp 
mov %esp,%ebp 
mov 8(%esp), %eax 
lidt (%eax) 
leave 
ret 

Это называется так:

static struct __InteruptDescriptorTableEntry InteruptDescriptorTable[NUM_IDT_ENTRIES]; 


void zeroIDT() 
{ 
    unsigned i; 
    for(i=0;i<NUM_IDT_ENTRIES-1;++i) 
    { 
     IDTEntry nullIDTEntry = fillIDTEntry(0,0,0); 
     registerInterupt(nullIDTEntry, i); 
    } 
} 

void registerInterupt(const IDTEntry entry, const unsigned intNo) 
{ 
    if(intNo < NUM_IDT_ENTRIES) 
     InteruptDescriptorTable[intNo] = entry; 
    else 
    { 
     __asm__("mov $0xDEADC0DE, %eax"); 
     __asm__("hlt"); 
    } 
} 

#define LOW_FUN_ADDR(fun) ((uint32_t)fun & 0xFFFF) 
#define UP_FUN_ADDR(fun) ((uint32_t)fun >> 16) & 0xFFFF 

IDTEntry fillIDTEntry(uint32_t intHandler, 
         uint16_t selector, 
         uint8_t type_attr) 

{ IDTEntry newEntry; 
    newEntry.offset_low = LOW_FUN_ADDR(intHandler); 
    newEntry.selector = selector; 
    newEntry.zero = 0;  
    newEntry.type_attr = type_attr; 
    newEntry.offset_up = UP_FUN_ADDR(intHandler); 
    return newEntry; 
} 

extern void _lidt(_IDT_PTR* idtPtr); 
void loadIDT() 
{ 
    zeroIDT(); 
    _IDT_PTR idtPtr; 
    idtPtr.idtSize = sizeof(struct __InteruptDescriptorTableEntry)*256 - 1; 
    idtPtr.idtBaseAddr = (uint32_t) &InteruptDescriptorTable; 

    IDTEntry printOnScreenInt = fillIDTEntry((uint32_t)interupt_pritnOnScreen, 0x18, 0xe); 
    registerInterupt(printOnScreenInt, 32); 
    _lidt(&idtPtr); 
} 

структуры данных:

struct __InteruptDescriptorTableEntry 
{ 
    uint16_t offset_low; 
    uint16_t selector; 
    uint8_t zero;  
    uint8_t type_attr; 
    uint16_t offset_up; 
} __attribute__((packed)); 
typedef struct __InteruptDescriptorTableEntry IDTEntry; 

struct _ITD_PTR 
{ 
    uint16_t idtSize; 
    uint32_t idtBaseAddr; 
} __attribute__((packed)); 
typedef struct _ITD_PTR _IDT_PTR; 

И пример Обработчик прерываний:

.global interupt_pritnOnScreen 
interupt_pritnOnScreen: 
    mov $0xf00ff00f, %eax 
    hlt 
iret 

Я проверил, если IDT регистр загружается с PTR к IDT в quemu, и это. Я загружаю IDT сразу после загрузки GRUB (установлен защищенный режим, а селектора GDT - по всей ОЗУ). Я думаю, что я неправильно регистрирую процедуры прерывания, но могу указать любую ошибку в своем коде.

ответ

2

В журнале четко указано not present. Вы забыли установить текущий бит в записи IDT. Вы должны использовать type_attr от 0x8E.